1. T/T的付款方式,产地证写错一个字母要不要紧?很急,给20分~!
不要紧,T/T是电汇,不是L/C
产地证就是目的港提货的时候需要用,我觉得最好改改,因为你不光光是地址错误。。SHIPING名称都错了,如果要求严格,可能目的港提货会有困难。。。
2. 外贸问题
外贸人员如何找客人
刚刚进公司时,主管给我三句话:
1)你永远不知道客人在想什么(所以不要花心思去猜);
2)你永远不知道自己做的对不对(所以做事情不要缩手缩脚);
3)你永远不知道今天的客户,明天会不会成为竞争对手(所以关系再好,有些事情也要保密)。
1.在工厂时,客人抱怨价格太高时,我总是说一分钱一分货,以质量好来回复。进入贸易公司后,才知道价格才是硬道理,特别是大客人,对价格的考虑绝对是高于对质量的考虑的。而且千万不要以为自己做不了的价格别人也做不了,在你这里一分钱的货,别的工厂半分钱就可以了。以电子厂为例,光是在广东东莞一个地方就有大大小小3000多家,客人的选择余地是非常大的。所以在客人威胁不降价就转单的时候,千万不要以为以他的价钱根本转不出去。
2.如果客人说要验厂的话,你的机会就来了,千万不要嫌麻烦,只有大客户才会在下单之前验厂的。
3.不要过分向有意愿的客户吹嘘现有的业绩。我曾经碰到有的业务,和我谈价格时,大谈他的一个大客户如何如何,说别人一个月200K的订单也是这个价格。这样的谈法,等于是在封我的嘴,我当时就感觉他已经吃撑了,再给饭也不要了。
4.答应的事情要做到,即使完成不了也要提前告诉客人,不要拖到客人来问才说。诚信太重要了,不只是公司,个人诚信也很重要,即使单子没做成,至少保住了在客人面前的诚信,无论是对业务,还是对自己将来的发展都大有好处。
5.报价要有技巧。居然有的工厂业务把价格报个天高(比其他工厂高3-4倍!!),还好意思说自己是因为质量过硬,在追问到底好在哪里,又说工程人员比较清楚,自己不知道!!客人都不傻,如果相同容量的MP3,报价比SONY还高的话,又有谁会感兴趣呢?
6.接到客人讯盘时要及时回复,即使是一封大众格式的回复都会让客人知道你办事的效率及对客人的尊重。有时候等你考虑好如何回复,报价时,客人已经飞掉了。对于那些在阿里或者资源上做广告,每天有大量讯盘的业务,这点尤其重要。
7.生意上的SENSE必不可少。这个东西比较难描述,简单的说是能够发现客人在考虑是否下单时,最主要的因素是什么。
8.不要轻易的对客人说”不”。圆滑的处理是好的选择。例如,客人的目标价格实在是做不下来,可以说”我再帮您和老板争取一下”,或者推荐可以达到目标价格的产品给客人。
9.参加展会时,最好在第一天去,因为除了第一天,大多数参展的业务都没有了激情,对于客人的寻价几乎是疲于应付。那些自以为有火眼睛睛的业务则对客人区别对待。这些都是很致命的。展会就那么几天,拜托各位打足12分精神,给每一个到你展位的客人良好的印象。
10.坐在办公室里,重复着千篇一律的工作,发邮件,收邮件......很多人干了几个月却没有订单,甚至一点头绪都没有。相信多数的业务员都经历过这样的情况。其实的客户开发很没有目的性,即,根本没抓重点客户,而是泛泛的联系,自然很难有成果。做业务,在开始向新客人发邮件前,一定要确认你的邮件对客人是有价值的。例如,如果你是做廉价小礼品的,又想开发美国市场,你就要知道目标客人是WAL-MART,DOLLAR TREE,DOLLAR GENERAL......做文具的就要知道目标客人是OFFICE MAX,OFFICE DEPOT......做家电的就要知道CIRCUITCITY, RADIO SHACK,STAPLES......这些客人只要攻下一家,业务量就够老板笑几个月了。
11.关于报价单的问题。现在的客户大都有自己的报价单格式,方便比较,但是有工厂的业务不能理解,甚至偷懒,总是不能及时,完整,正确的填写,总觉得自己的报价单就OK了,不需要再填那么复杂的东西。但是站在客人的立场上,如果一个工厂的业务人员,连报价单那么简单的东西都做不好,怎么会放心把订单交给你呢。
12.关于商业技巧的问题。如果大家想成为真正的业务的话,就要注意一下外贸以外的东西,我是指除了单证,报关等等只有外贸才会涉及的东西,还要多多向国内的业务员学习业务的技巧。这一点我以前也发过帖子,不过并没有得到广泛的认同,而本人在实践中深刻感受到外贸业务在如何做生意,以及商业嗅觉上比国内的业务员差的好多。大家虽然面对的市场和客人不同,但是,商业的技巧是互通的。
13.关于付款方式。做外贸生意,付款风险大,所以,在考虑付款方式时,要首先注意控制风险,这个道理大家都明白,那么,如果客人的付款方式和你的风险控制发生冲突,影响成交时,该如何既拿到订单,又确保收款呢。去找中国出口信用保险公司,虽然手续复杂,但是一旦承保,绝对安全。
14.业务和老板的关系。在和工厂谈判时,明显感觉到和老板谈比和业务谈有效果,因为业务永远都不知道老板的底线在哪里,这就带出一个问题,业务在准备谈判时,到底该知道多少。千万不要以为老板把BOM单丢给你,就是对你的信任了,如何把握老板的心态,也是业务员要学习的东西,特别是在价格谈不拢时。
15.这一条要特别送给工厂的业务员。工厂,特别是大工厂的业务,服务意识很差。这里的服务不是说客人来了端茶倒水,而是说在日常与客人交流和处理问题上,要有不光做好产品,还要做好服务的意识。例如,我要一个业务帮我处理样品的事情,他做着做着就烦了,抱怨说他的客人中我是最烦人的一个。试想,如果饭店服务员一边给人倒茶一边埋怨客人,他还能干下去吗。这里要提醒一些年轻的女业务,不要在客人面前耍小姐脾气或者撒娇,即使平时和客人关系再好也不可以,外贸生意讲究的是严谨,细致的作风,切不可在客人面前显示出小女人的面目。
16.现在有的营销书上强调业务员在见客户时,一定要不卑不亢。但是很多业务只做到了不卑,在客户面前很酷。酷也就算了,很多问题一问三不知,连工厂的基本状况都还不了解,而且摆出一副”你的问题真可笑”的表情。看来,做到不卑很容易,但是同时做到不亢,就不是那么简单了。
17.在学校里,都会学过一些营销方面的课程,其中心理学的内容也有涉及,不过现在看起来,那些东西不是我辈这种没几年社会经历的人能掌握的,特别是做外贸的,本来人际关系就比较简单,想要在谈判中准确把握客人的心理基本是不可能的。所以,没有足够复杂的思想,就不要浪费时间和精力去猜测客人在想什么,更不要基于猜测做任何的判断,所有的判断一定要有事实做基础。
18.一份客户联系名单是很重要的,最好是在自己的OUTLOOK里编一份,每隔一段时间就发一些新产品拉,报价拉之类的,虽然只是举手之劳,但是却可以让客人对你保持印象。其实,有价值的客人是有限的,在经过了前期的散网和筛选后,如何让有潜力的客人下单就变成第一要务,而让客人保持对你的印象是成功的第一步。
19.客人也是人,也会发昏犯错,也会不礼貌,所以,对于那些不骂不足以平民愤的客人,一定要骂,而且要狠狠的骂,不过,骂完之后,一定要打电话解释,说自己太年轻,比较冲动之类的适当安抚一下,既除了胸中闷气,又不得罪客人。
20.我在工厂做业务时,经常觉得采购和财务比客人还要难对付,很多的时间和精力都花在内耗上了。现在想起来,要得到公司内部的支持,就一定在平时就注意搞好人际关系,切忌目空一切骄傲自大。
1.客户询盘:一般在客户下订单之前,都会有相关的Order Inquiry给业务部,做一些细节上的了解。
2.报价:业务部及时回复客人查询,确定货物品名,型号,生产厂家,数量,交货期,付款方式,包装规格及柜型等,Performa Invoice 给客户做正式报价。
3.得到订单:经过洽谈,收到客户正式的订单purchase Order。
4.下生产订单:得到客人的订单确认后,给工厂下订单,安排生产计划。
5.业务审批:业务部收到订单后,首先做出业务审核表。按"出口合同审核表"的项目如实填写,尽可能将各种预计费用都列明。合同审批需附上客人订单传真件,与工厂的收购合同。审核表要由业务员签名,部门经理审批,再交管理部人员审核后才能执行。如金额较大的,或有预付款和佣金等条款的,要经公司总经理审批才行。合同审批之后,制成销售订单,交给部门进程员跟进。
6.下达生产通知:业务部在确定交货期后,满足下列情况可下达生产通知, 通知工厂按时生产: 6.1:如果是L/C付款的客户,通常是在交货期前1个月确认L/C已经收到,收到L/C后应业务员和单证员分别审查信用证,检查是否存在错误,交货期能否保障,及其他可能的问题,如有问题应立即请客人改证。 6.2:如果是T/T付款的客户,要确认定金已经到账。 6.3:如果是放帐客户,或通过银行D/A等方式收汇等,需经理确认。
7. 验货 7.1:在交货期前一周,要通知公司验货员验货。 7.2:如果客人要自己或指定验货人员来验货的,要在交货期一周前,约客户查货并将查货日期告知计划部。 7.3:如果客人指定由第三方验货公司或公正行等验货的,要在交货期两周前与验货公司联系,预约验货时间,确保在交货期前安排好时间。确定后将验货时间通知工厂。
8.制备基本文件。工厂提供的装箱资料,制作出口合同,出口商业发票,装箱单等文件(应由业务跟单员制作,交给单证员)。
9.商检:如果是国家法定商检产品,在给工厂下订单时要说明商检要求,并提供出口合同,发票等商检所需资料。而且要告诉工厂将来产品的出口口岸,便于工厂办理商检。应在发货一周之前拿到商检换证凭单/条。
(以下是船务流程)
10. 租船订仓: 10.1.如果跟客人签定的合同是FOB CHINA条款,通常客人会指定运输代理公司或船公司。应尽早与货代联系,告知发货意向,了解将要安排的出口口岸,船期等情况,Q确认工厂的交货能否早于开船期至少一周以前,以及船期能否达到客人要求的交货期。应在交货期两周之前向货运公司发出书面定仓通知(ING ORDER),通常在开船一周前可拿到定仓纸。 10.2.如果是由卖方支付运费,应尽早向货运公司或船公司咨询船期,运价,开船口岸等。经比较,选择价格优惠,信誉好,船期合适的船公司,并告诉业务员通告给客人。如客人不同意时要另选客人认可的船公司。开船前两周书面定仓,程序同上。 10.3.如果货物不够一个小柜,需走散货时,向货代公司定散货仓位。拿到入仓纸时,还要了解截关时间,入仓报关要求,等内容。 10.4.向运输公司定仓时,一定要传真书面定仓纸,注明所定船期,柜型及数量,目的港等内容,以避免差错。
11. 安排拖柜: 11.1.货物做好并验货通过后,委托拖车公司提柜,装柜。拖车公司应选择安全可靠,价格合理的公司签定协议长期合作,以确保安全及准时。要给拖车公司传真以下资料:定仓确认书/放柜纸,船公司,定仓号,拖柜委托书,注明装柜时间,柜型及数量,装柜地址,报关行,及装船口岸等。如果有验货公司看装柜,要专门声明,不能晚到。并要求回传一份上柜资料,列明柜号、车牌号、司机及联系电话等 11.2.传真一份装车资料给工厂,列明上柜时间、柜型、订仓号、订单号、车牌号以及司机联系电话。 11.3.要求工厂在货柜离开工厂后尽快传真一份装货通知给业务部,列明货柜离厂时间、实际装货数量等,并记装箱号码和封条号码作为提单的资料。要求工厂装柜后一定要记住上封条。
12.委托报关:在拖柜同时将报关所需资料交给合作报关行,委托出口报关及做商检通关换单。通常要给报关留出两天时间(船截关前)。委托报关时,应提供一份装柜资料,内容包括所装货物及数量,口岸,船公司,定仓号,柜号,船开截关时间,拖车公司,柜型及数量,本公司的联系人和电话等。
13. 获得运输文件: 13.1. 最迟在开船后两天内,要将提单补料内容传真给船运公司或货运代理。补料要按找L/C或客人的要求来做,并给出正确的货物数量,以及一些特殊要求等,包括要求船公司随同提单出的船证明等。 13.2. 督促船公司尽快出提单样板及运费帐单。仔细核对样本无误后,向船公司书面确认提单内容。如果提单需客人确认的,要先传真提单样板给客人,得到确认后再要求船公司出正本。 13.3. 及时支付运杂费,付款后通知船公司及时取得提单等运输文件。支付运费应做登记。
14. 准备其他文件 14.1.商业发票:L/C 要求提供的文件中,对商业发票要求最严格。发票的日期要确定在开证日之后,交货期之前。发票中的货物描述要与L/C上的完全相同,小写和大写金额都要正确无误。L/C上对发票的条款应显示出来,要显示唛头。如果发票需办理对方大使馆认证,一般要提前20天办理。 14.2.FORMA原产地证书:FORM A 原产地证要在发货之前到检验检疫局申办。需注意的是运输日期要在L/C 的交货期和开船日之前,在发票日期之后。未能在发货之前办理的,要办理后发证书,需提供报关单,提单等文件。经香港转运的货物,FORM A证书通常要到香港的中国商检公司办理加签,证明未在港对货物进行再加工。 14.3.一般原产地证:一般原产地证可在中国贸易促进会办理,要求低一些。可在发货之后不太长的时间内补办。如果原产地证书要办理大使馆加签,也和发票一样要提前20天办理。 14.4.装运通知:一般是要求在开船后几天之内,要通知客人发货的细节,包括船名,航班次,开船日,预计抵港日,货物及数量,金额,包装件数,唛头,目的港代理人等。有时L/C要求提供发送证明,如传真报告书,发函底单等,注意按客人要求的时间内办理。 14.5.装箱单:装箱单应清楚地表明货物装箱情况。要显示每箱内装的数量,每箱的毛重,净重,外箱尺寸。按外箱尺寸计算出来的总体积要与标明的总体积相符。要显示唛头和箱号,以便于客人查找。装箱单的重量,体积要于提单相符。
15.交单: 15.1.采用L/C收汇的,应在规定的交单时间内,备齐全部单证,并严格审单,确保没有错误,才交银行议付。 15.2.采用T/T收汇的,在取得提单后马上传真提单给客人付款,确认受到余款后再将提单正本及其他文件寄给客人。 15.3.如果T/T收汇的,要求收全款才能做柜的,要等收款后再安排拖柜。拿到提单后可立即寄正本提单给客人。
16.业务登记:每单出口业务在完成后要及时做登记,包括电脑登记及书面登记,便于以后查询,统计等。
17.文件存档:所有的文件、L/C和议付文件必须留存一整套以备查用。
18.单证员平时应注意收集运价变动,船期,航线,等信息,为业务员报价提供帮助
3. 外贸中的T/T是什么样的付款方式?
电汇---Telegraphic Transfer T/T
电汇是汇出行应汇款人的申请,拍发加押电报或电传(Tested Cable/Telex)或者通过SWIFT给国外汇入行,指示其解付一定金额给收款人的一种汇款结算方式。
电汇以电报、电传作为结算工具,安全迅速、费用也较高,由于电报电传的传递方向与资金的流向是相同的,因此电汇属于顺汇。
电汇是目前使用较多的一种汇款方式,其业务流程是:先由汇款人电汇申请书并交款付费给汇出行,在由汇出行拍加押电报或电传给汇入行,汇入行给收款人电汇通知书,收款人接到通知后去银行兑付,银行进行解付,解付完毕汇入行发出借记通知书给汇出行,同时汇出行给汇款人电汇回执。
电汇时,由汇款人填写汇款申请书,并在申请书中注明采用电汇T/T方式。同时,将所汇款项及所需费用交汇出行,取得电汇回执。汇出行接到汇款申请书后,为防止因申请书中出现的差错而耽误或引起汇出资金的意外损失,汇出行应仔细审核申请书,不清楚的地方与汇款人及时联系。
汇出行办理电汇时,根据汇款申请书内容以电报或电传向汇入行发出解付指示。电文内容主要有:汇款金额及币种、收款人名称、地址或帐号、汇款人名称、地址、附言、头寸拨付办法、汇出行名称或SWIFT地址等。为了使汇入行证实电文内容确实是由汇出行发出的,汇出行在正文前要加列双方银行所约定使用的密押(Testkey)。
汇入行收到电报或电传后,即核对密押是不是相符,若不符,应立即拟电文向汇出行查询。若相符,即缮制电汇通知书,通知收款人取款。收款人持通知书一式两联向汇入行取款,并在收款人收据上签章后,汇入行即凭以解付汇款。实务中,如果收款人在汇入行开有帐户,汇入行往往不缮制汇款通知书,仅凭电文将款项收入收款人收户,然后给收款人一收帐通知单,也不需要收款人签具收据。最后,汇入行将付讫借记通知书(Debit Advice)寄给汇出行。
电汇中的电报费用由汇款人承担,银行对电汇业务一般均当天处理,不占用邮递过程的汇款资金,所以,对于金额较大的汇款或通过SWIFT或银行间的汇划,多采用电汇方式。
TT,虽然有一定的风险,但是费用低,现在在世界的外贸付款方式中很流行.
一共有几种方式吧,
1.100%前TT,这种方式很少见,如果你的客人在下单的时候给你100%TT过来,那么你走运了.这个客人应该是老客人或者金额比较小才会这么做.
2.100%后TT,这个有一定的风险性,除非是老客人,否则我们就太被动了,随时都有可能钱货两空,付不付款全靠客人的信用.
3.30%前TT(作定金),70%后TT,见提单付本付款,这种是最为常见的.
4. 我的是校园网,可是在连接时!出现一个MAC地址绑定错误,有谁能告诉我是该怎么办啊!!!
你的IP填错了吧,貌似不是你自己的。以前你的电脑能在那里上网吗,还是刚出现的问题?最好联系管理员
补充:明白了,你们学校是绑定了IP上网的,你现在换了台电脑是没在你们学校绑定过的,插在那里不能用的,联系管理员绑定你的新电脑
5. 运行出错!错误信息:无法找到指定DLL库文件“SkinH_EL.dll”中的输出命令
当我们使用关键字new在堆上动态创建一个对象时,它实际上做了三件事:获得一块内存空间、调用构造函数、返回正确的指针。当然,如果我们创建的是简单类型的变量,那么第二步会被省略。假如我们定义了如下一个类A: class A { int i; public: A(int _i) :i(_i*_i) {} void Say() { printf("i=%dn", i); } }; //调用new: A* pa = new A(3); 那么上述动态创建一个对象的过程大致相当于以下三句话(只是大致上): A* pa = (A*)malloc(sizeof(A)); pa->A::A(3); return pa; 虽然从效果上看,这三句话也得到了一个有效的指向堆上的A对象的指针pa,但区别在于,当malloc失败时,它不会调用分配内存失败处理程序new_handler,而使用new的话会的。因此我们还是要尽可能的使用new,除非有一些特殊的需求。
new的三种形态
到目前为止,本文所提到的new都是指的“new operator”或称为“new expression”,但事实上在C++中一提到new,至少可能代表以下三种含义:new operator、operator new、placement new。 new operator就是我们平时所使用的new,其行为就是前面所说的三个步骤,我们不能更改它。但具体到某一步骤中的行为,如果它不满足我们的具体要求 时,我们是有可能更改它的。三个步骤中最后一步只是简单的做一个指针的类型转换,没什么可说的,并且在编译出的代码中也并不需要这种转换,只是人为的认识 罢了。但前两步就有些内容了。 new operator的第一步分配内存实际上是通过调用operator new来完成的,这里的new实际上是像加减乘除一样的操作符,因此也是可以重载的。operator new默认情况下首先调用分配内存的代码,尝试得到一段堆上的空间,如果成功就返回,如果失败,则转而去调用一个new_hander,然后继续重复前面 过程。如果我们对这个过程不满意,就可以重载operator new,来设置我们希望的行为。例如: class A { public: void* operator new(size_t size) { printf("operator new calledn"); return ::operator new(size); } }; A* a = new A(); 这里通过::operator new调用了原有的全局的new,实现了在分配内存之前输出一句话。全局的operator new也是可以重载的,但这样一来就不能再递归的使用new来分配内存,而只能使用malloc了: void* operator new(size_t size) { printf("global newn"); return malloc(size); } 相应的,delete也有delete operator和operator delete之分,后者也是可以重载的。并且,如果重载了operator new,就应该也相应的重载operator delete,这是良好的编程习惯。 new的第三种形态——placement new是用来实现定位构造的,因此可以实现new operator三步操作中的第二步,也就是在取得了一块可以容纳指定类型对象的内存后,在这块内存上构造一个对象,这有点类似于前面代码中的“p- >A::A(3);”这句话,但这并不是一个标准的写法,正确的写法是使用placement new: #include void main() { char s[sizeof(A)]; A* p = (A*)s; new(p) A(3); //p->A::A(3); p->Say(); } 对头文件或的引用是必须的,这样才 可以使用placement new。这里“new(p) A(3)”这种奇怪的写法便是placement new了,它实现了在指定内存地址上用指定类型的构造函数来构造一个对象的功能,后面A(3)就是对构造函数的显式调用。这里不难发现,这块指定的地址既 可以是栈,又可以是堆,placement对此不加区分。但是,除非特别必要,不要直接使用placement new ,这毕竟不是用来构造对象的正式写法,只不过是new operator的一个步骤而已。使用new operator地编译器会自动生成对placement new的调用的代码,因此也会相应的生成使用delete时调用析构函数的代码。如果是像上面那样在栈上使用了placement new,则必须手工调用析构函数,这也是显式调用析构函数的唯一情况: p->~A(); 当我们觉得默认的new operator对内存的管理不能满足我们的需要,而希望自己手工的管理内存时,placement new就有用了。STL中的allocator就使用了这种方式,借助placement new来实现更灵活有效的内存管理。
处理内存分配异常
正如前面所说,operator new的默认行为是请求分配内存,如果成功则返回此内存地址,如果失败则调用一个new_handler,然后再重复此过程。于是,想要从operator new的执行过程中返回,则必然需要满足下列条件之一: l 分配内存成功 l new_handler中抛出bad_alloc异常 l new_handler中调用exit()或类似的函数,使程序结束 于是,我们可以假设默认情况下operator new的行为是这样的: void* operator new(size_t size) { void* p = null while(!(p = malloc(size))) { if(null == new_handler) throw bad_alloc(); try { new_handler(); } catch(bad_alloc e) { throw e; } catch(…) {} } return p; } 在默认情况下,new_handler的行为是抛出一个bad_alloc异常,因此 上述循环只会执行一次。但如果我们不希望使用默认行为,可以自定义一个new_handler,并使用std::set_new_handler函数使其 生效。在自定义的new_handler中,我们可以抛出异常,可以结束程序,也可以运行一些代码使得有可能有内存被空闲出来,从而下一次分配时也许会成 功,也可以通过set_new_handler来安装另一个可能更有效的new_handler。例如: void MyNewHandler() { printf(“New handler called!n”); throw std::bad_alloc(); } std::set_new_handler(MyNewHandler); 这里new_handler程序在抛出异常之前会输出一句话。应该注意,在 new_handler的代码里应该注意避免再嵌套有对new的调用,因为如果这里调用new再失败的话,可能会再导致对new_handler的调用, 从而导致无限递归调用(没有尝试过)。 在编程时我们应该注意到对new的调用是有可能有异常被抛出的,因此在new的代码周围应该注意保持其事务性,即不能因为调用new失败抛出异常来导致不正确的程序逻辑或数据结构的出现。例如: class SomeClass { static int count; SomeClass() {} public: static SomeClass* GetNewInstance() { count++; return new SomeClass(); } }; 静态变量count用于记录此类型生成的实例的个数,在上述代码中,如果因new分配内存失败而抛出异常,那么其实例个数并没有增加,但count变量的值却已经多了一个,从而数据结构被破坏。正确的写法是: static SomeClass* GetNewInstance() { SomeClass* p = new SomeClass(); count++; return p; } 这样一来,如果new失败则直接抛出异常,count的值不会增加。类似的,在处理线程同步时,也要注意类似的问题: void SomeFunc() { lock(someMutex); //加一个锁 delete p; p = new SomeClass(); unlock(someMutex); } 此时,如果new失败,unlock将不会被执行,于是不仅造成了一个指向不正确地址的指针p的存在,还将导致someMutex永远不会被解锁。这种情况是要注意避免的。(参考:C++箴言:争取异常安全的代码)
STL的内存分配与traits技巧
在《STL原码剖析》一书中详细分析了SGI STL的内存分配器的行为。与直接使用new operator不同的是,SGI STL并不依赖C++默认的内存分配方式,而是使用一套自行实现的方案。首先SGI STL将可用内存整块的分配,使之成为当前进程可用的内存,当程序中确实需要分配内存时,先从这些已请求好的大内存块中尝试取得内存,如果失败的话再尝试 整块的分配大内存。这种做法有效的避免了大量内存碎片的出现,提高了内存管理效率。 为了实现这种方式,STL使用了placement new,通过在自己管理的内存空间上使用placement new来构造对象,以达到原有new operator所具有的功能。 template inline void construct(T1* p, const T2& value) { new(p) T1(value); } 此函数接收一个已构造的对象,通过拷贝构造的方式在给定的内存地址p上构造一个新对 象,代码中后半截T1(value)便是placement new语法中调用构造函数的写法,如果传入的对象value正是所要求的类型T1,那么这里就相当于调用拷贝构造函数。类似的,因使用了 placement new,编译器不会自动产生调用析构函数的代码,需要手工的实现: template inline void destory(T* pointer) { pointer->~T(); } 与此同时,STL中还有一个接收两个迭代器的destory版本,可将某容器上指定范 围内的对象全部销毁。典型的实现方式就是通过一个循环来对此范围内的对象逐一调用析构函数。如果所传入的对象是非简单类型,这样做是必要的,但如果传入的 是简单类型,或者根本没有必要调用析构函数的自定义类型(例如只包含数个int成员的结构体),那么再逐一调用析构函数是没有必要的,也浪费了时间。为 此,STL使用了一种称为“type traits”的技巧,在编译器就判断出所传入的类型是否需要调用析构函数: template inline void destory(ForwardIterator first, ForwardIterator last) { __destory(first, last, value_type(first)); } 其中value_type()用于取出迭代器所指向的对象的类型信息,于是: template inline void __destory(ForwardIterator first, ForwardIterator last, T*) { typedef typename __type_traits::has_trivial_destructor trivial_destructor; __destory_aux(first, last, trivial_destructor()); } //如果需要调用析构函数: template inline void __destory_aux(ForwardIterator first, ForwardIterator last, __false_type) { for(; first inline void __destory_aux(ForwardIterator first, ForwardIterator last, __true_type) {} 因上述函数全都是inline的,所以多层的函数调用并不会对性能造成影响,最终编译 的结果根据具体的类型就只是一个for循环或者什么都没有。这里的关键在于__type_traits这个模板类上,它根据不同的T类 型定义出不同的has_trivial_destructor的结果,如果T是简单类型,就定义为__true_type类型,否则就定义为 __false_type类型。其中__true_type、__false_type只不过是两个没有任何内容的类,对程序的执行结果没有什么意义,但在编译器看来它对模板如何特化就具有非常重要的指导意义了,正如上面代码所示的那样。__type_traits也是特化了的一系列模 板类: struct __true_type {}; struct __false_type {}; template struct __type_traits { public: typedef __false _type has_trivial_destructor; …… }; template //模板特化 struct __type_traits //int的特化版本 { public: typedef __true_type has_trivial_destructor; …… }; …… //其他简单类型的特化版本 如果要把一个自定义的类型MyClass也定义为不调用析构函数,只需要相应的定义__type_traits的一个特化版本即可: template struct __type_traits { public: typedef __true_type has_trivial_destructor; …… }; 模板是比较高级的C++编程技巧,模板特化、模板偏特化就更是技巧性很强的东西, STL中的type_traits充分借助模板特化的功能,实现了在程序编译期通过编译器来决定为每一处调用使用哪个特化版本,于是在不增加编程复杂性的 前提下大大提高了程序的运行效率。更详细的内容可参考《STL源码剖析》第二、三章中的相关内容。
带有“[]”的new和delete
我们经常会通过new来动态创建一个数组,例如: char* s = new char[100]; …… delete s; 严格的说,上述代码是不正确的,因为我们在分配内存时使用的是new[],而并不是简单的new,但释放内存时却用的是delete。正确的写法是使用delete[]: delete[] s; 但是,上述错误的代码似乎也能编译执行,并不会带来什么错误。事实上,new与new[]、delete与delete[]是有区别的,特别是当用来操作复杂类型时。假如针对一个我们自定义的类MyClass使用new[]: MyClass* p = new MyClass[10]; 上述代码的结果是在堆上分配了10个连续的MyClass实例,并且已经对它们依次调 用了构造函数,于是我们得到了10个可用的对象,这一点与Java、C#有区别的,Java、C#中这样的结果只是得到了10个null。换句话说,使用 这种写法时MyClass必须拥有不带参数的构造函数,否则会发现编译期错误,因为编译器无法调用有参数的构造函数。 当这样构造成功后,我们可以再将其释放,释放时使用delete[]: delete[] p; 当我们对动态分配的数组调用delete[]时,其行为根据所申请的变量类型会有所不 同。如果p指向简单类型,如int、char等,其结果只不过是这块内存被回收,此时使用delete[]与delete没有区别,但如果p指向的是复杂 类型,delete[]会针对动态分配得到的每个对象调用析构函数,然后再释放内存。因此,如果我们对上述分配得到的p指针直接使用delete来回收, 虽然编译期不报什么错误(因为编译器根本看不出来这个指针p是如何分配的),但在运行时(DEBUG情况下)会给出一个Debug assertion failed提示。
为对象调用析构函数
要回答这个问题,我们可以首先看一看new[]的重载。 class MyClass { int a; public: MyClass() { printf("ctorn"); } ~MyClass() { printf("dtorn"); } }; void* operator new[](size_t size) { void* p = operator new[](size); printf("calling new[] with size=%d address=%pn", size, p); return p; } // 主函数 MyClass* mc = new MyClass[3]; printf("address of mc=%pn", mc); delete[] mc; 运行此段代码,得到的结果为:(VC2005) calling new[] with size=16 address=003A5A58 ctor ctor ctor address of mc=003A5A5C dtor dtor dtor 虽然对构造函数和析构函数的调用结果都在预料之中,但所申请的内存空间大小以及地址的 数值却出现了问题。我们的类MyClass的大小显然是4个字节,并且申请的数组中有3个元素,那么应该一共申请12个字节才对,但事实上系统却为我们申 请了16字节,并且在operator new[]返后我们得到的内存地址是实际申请得到的内存地址值加4的结果。也就是说,当为复杂类型动态分配数组时,系统自动在最终得到的内存地址前空出了 4个字节,我们有理由相信这4个字节的内容与动态分配数组的长度有关。通过单步跟踪,很容易发现这4个字节对应的int值为0x00000003,也就是 说记录的是我们分配的对象的个数。改变一下分配的个数然后再次观察的结果证实了我的想法。于是,我们也有理由认为new[] operator的行为相当于下面的伪代码: template T* New[](int count) { int size = sizeof(T) * count + 4; void* p = T::operator new(size); *(int*)p = count; T* pt = (T*)((int)p + 4); for(int i = 0; i void Delete[](T* pt) { int count = ((int*)pt)[-1]; for(int i = 0; i < count; i++) pt.~T(); void* p = (void*)((int)pt – 4); T::operator delete(p); } 由此可见,在默认情况下operator new[]与operator new的行为是相同的,operator delete[]与operator delete也是,不同的是new operator与new[] operator、delete operator与delete[] operator。当然,我们可以根据不同的需要来选择重载带有和不带有“[]”的operator new和delete,以满足不同的具体需求。
6. 我填手机号的时候不小心写错了一位数,但又改不过来了,怎么办啊!当当会打电话到手机上吗 哎
你最好和你买东西的店主联系一下(一般都是有QQ或者其他的。。)声明一下
因为当当网是快递公司送货,货到了就是通过手机和你联系的~~~要是错了就找不到你哦~~~呵呵
7. 我是oppoa57t,不小心点了开发者模式,可它出现这个怎么办啊?不敢输验证码,想关闭它,挺急的!
依次进入【设置】——【关于手机】,找到【版本号】连续点击10次左右,即可开启开发者选项。如果还持续点击则会出现提示“您已处于开发者模式,无需进行此此操作”。回到手机【设置】——【其他设置】,点击进入,在页面底端就会出现【开发者选项】。进入【开发者选项】,即可关闭 。您按提示操作,输入验证码进入后,再选择退出即可。
8. 关于sat考试违纪的问题(很急!!!答得好追分!!!)
第一次违规一定有事。他的"I know"真正的意思是虽然你没有开始动手做,但是时间未到先看到题目已经违规,按照规定必须报告CB,而且他也确实告诉你他准备如此做。先翻下节考题及做回头题是两项最普遍的违规。
第二次违规应该没事。
因为违反考试程序,申诉不会有什麼用。怕就只能怕了,等几个礼拜再说吧,万一真被取消就这次是模拟考,这两件事当个作事该一板一眼的教训。