为什么用户定义的移动构造函数禁用隐含显示定义拷贝构造函数数

在读取 boost/shared_ptr 。hpp时,我看到了以下代码:
//generated copy constructor, destructor are fine...
#if defined( BOOST_HAS_RVALUE_REFS )
//... except in C++0x, move disables the implicit copy
shared_ptr( shared_ptr const & r ): px( r.px ), pn( r.pn )//never throws
注释"生成的复制构造函数,析构函数除了在C++11中很好之外,移动禁用隐式复制"在这里意味着什么? 我们是否总是自己编写副本来防止在C++11中出现这种情况?
17年06月03日
我有upvoted的答案,因为我发现它既准确又幽默。 :- )
我提供了另一个答案,因为我假设,由于这个问题的标题,OP可能需要知道 ,原因是standard标准 says 。
C++ 隐式生成副本成员因为如果它没有,它将在 1985 still-born因为所以不兼容c。 在这种情况下,我们今天不会有这个对话,因为 C++ 不存在。
也就是说,隐式生成的复制成员类似于"处理恶魔"。 C++ 不能没有它们就诞生了。 但它们是邪恶的,因为它们在大量实例中生成不正确的代码。 C++ 委员会并不愚蠢,他们知道这个。
现在 C++ 已经诞生,并且已经演变为一个成功的grownup,委员会只想说: 我们不再进行隐式生成的复制成员。 它们太危险了。如果你想要一个隐式生成的复制成员,你必须opt-in到该决策( 与它的opt-out相反) 。 然而,考虑到现有的C++ 代码的数量,如果这些代码会中断,那么就等于自杀。 有一个巨大向后兼容性担心是很有道理的。
因此,委员会达到了一个折衷的位置: 如果你声明移动成员( 哪些旧版 C++ 代码无法执行),那么我们将假设默认复制成员可能会做错误的事情。 Opt-in ( 使用 =default ) 如果你想要它们。 或者自己写。否则会被隐式删除。 经验to-date世界move-only类型表明这个默认位置是很常见的期望( 比如 。 unique_ptr,ofstream,future,等等 ) 。 而opting-in的开销实际上是非常小的= default 。
英镑的远期
委员会愿意说: 如果你已经编写了析构函数,那么隐式复制成员可能不正确,所以我们将删除它们。 这是 c++98/03"三个规则"。 尽管那样会破坏很多代码。 但是,委员会在C++11中说,如果提供了user-declared析构函数,则复制成员的隐式生成将被低估为 。 这意味着这个功能可以在未来的标准中删除。 而且,现在你的编译器可能会在这种情况下开始问题"过时的警告"。
警告:C++ 已经成长并成熟了几十年。 这意味着你父亲的C++ 可能需要迁移来处理你的孩子的C++ 。 这是一个缓慢缓慢的过程,这样你就不会放弃你的手,只移植到另一个语言。 但它的是 change,即使是缓慢的。
因为 C++ 标准表示- §12.8/7:
如果类定义没有显式声明复制构造函数,则声明为隐式 。 如果类定义声明一个构造函数或移动赋值运算符,隐式声明的拷贝构造函数被定义为删除;否则,它被定义为违约。 如果类具有user-declared复制赋值运算符或者user-declared析构函数,则不推荐使用后者。 因此,对于类定义
struct X {
X(const X&, int);
复制构造函数是 implicitly-declared 。 如果user-declared构造函数后来被定义为
X::X(const X& x, int i =0) {/*.. . */}
然后,任何使用ill-formed构造函数的副本都是,因为不明确;不需要诊断。
( 强调我的) 。
Copyright (C) 2011 HelpLib All rights reserved. &&C++构造函数和拷贝构造函数详解
时间: 16:26:50
&&&& 阅读:62
&&&& 评论:
&&&& 收藏:0
标签:&&&&&&&&&&&&&&&&&&&&&&&&&&&构造函数、析构函数与赋值函数是每个类最基本的函数。它们太普通以致让人容易麻痹大意,其实这些貌似简单的函数就象没有顶盖的下水道那样危险。
每个类只有一个析构函数和一个赋值函数,但可以有多个构造函数(包含一个拷贝构造函数,其它的称为普通构造函数)。
对于任意一个类A,如果不想编写上述函数,C++编译器将自动为A 产生四个缺省的函数,例如:
&&&&&&& A(void); // 缺省的无参数构造函数
&&&&&&& A(const A &a); // 缺省的拷贝构造函数
&&&&&&& ~A(void); // 缺省的析构函数
&&&&&&& A & operate =(const A &a); // 缺省的赋值函数
这不禁让人疑惑,既然能自动生成函数,为什么还要程序员编写?原因如下:
&&&&&& &1&如果使用&缺省的无参数构造函数&和&缺省的析构函数&,等于放弃了自主&初始化&和&清除&的机会,C++发明人Stroustrup 的好心好意白费了。
&&&&&& &2&&缺省的拷贝构造函数&和&缺省的赋值函数&均采用&位拷贝&而非&值拷贝&的方式来实现,倘若类中含有指针变量,这两个函数注定将出错。
C++ 默认构造函数 :
1、每个类必须有一个构造函数,否则没法创建对象; 2、若 程序员没有提供任何构造函数,则
C++提供一个默认的构造函数,该默认构造函数是无参构造函数,它仅负责创建对象,不做任何初始化的工作; 3、只要 programer
定义了一个构造函数(不管是无参还是有参构造),C++就不再提供默认的默认构造函数。即如果为类定义了一个带参的构造函数,还想要无参构造函数,就必须自己定义;
4、与变量定义类似,在用默认构造函数创建对象时,如果创建的是全局对象或静态对象,则对象的位模式全为
0,否则,对象值是随机的。
C++默认拷贝构造函数:1、默认的拷贝构造函数执行的顺序与其他用户定义的构造函数相同,执行先父类后子类的构造.2、拷贝构造函数对类中每一个数据成员执行成员拷贝(memberwise
Copy)的动作.3、如果数据成员为某一个类的实例,那么调用此类的拷贝构造函数.4、如果数据成员是一个数组,对数组的每一个执行按位拷贝.
5、如果数据成员是一个数量,如int,double,那么调用系统内建的赋值运算符对其进行赋值.
请看下面代码:
#include &iostream&
#include &string&
class Student
cout && "构造函数1" &&
Student(int k)
cout && "构造函数2" &&
Student(Student const &m)
cout && "拷贝构造函数" &&
i = m.i * (-1);
cout && i &&
~Student()
cout && "析构函数" &&
protected:
int main(int argc, char **argv)
Student s(9818);
// 调用构造函数2
Student t(s);
// 调用拷贝构造函数
Student k =
// 调用拷贝构造函数
Student *p = new Student(s);
// 调用拷贝构造函数
// 调用构造函数1
m =// 赋值运算
  运行结果:
拷贝构造函数
拷贝构造函数
拷贝构造函数
下面我们来讨论一下关于浅拷贝和深拷贝的问题。&
&&&&&&& 深拷贝和浅拷贝的定义可以简单理解成:如果一个类拥有资源(堆,或者是其它系统资源),当这个类的对象发生复制过程的时候(复制指针所指向的值),这个过程就可以叫做深拷贝,反之对象存在资源但复制过程并未复制资源(只复制了指针所指的地址)的情况视为浅拷贝。  很多人会问到,既然系统会自动提供一个默认的拷贝构造函数来处理复制,那么我们没有必要去自定义拷贝构造函数呀,对,就普通情况而言这的确是没有必要的,但在某些状况下,类体内的成员是需要开辟动态堆内存的,如果我们不自定义拷贝构造函数而让系统自己处理,那么就会导致堆内存的所属权产生混乱。试想一下,已经开辟的一端堆地址原来是属于对象a的,由于复制过程发生,b对象取得是a已经开辟的堆地址,一旦程序产生析构,释放堆的时候,计算机不清楚这段地址是真正属于谁的,当连续发生两次析构的时候就出现了运行错误。  为了更详细的说明问题,请看如下的代码。
#include &iostream&
#include &string&
using namespace
cout && "调用构造函数" &&
f = new char[10];
cout && "调用析构函数" &&
int main(int argc, char **argv)
printf("p.f=%p\n",p.f);
strcpy(p.f, "Computer");
cout && p.f &&
aa q(p);// 调用默认的拷贝构造函数
printf("q.f=%p\n",q.f);
cout && q.f &&
strcpy(p.f, "Software");
cout && p.f &&
cout && q.f &&
strcpy(q.f, "Software");
cout && p.f &&
cout && q.f &&
运行结果:
调用构造函数
p.f=003F1048
q.f=003F1048
调用析构函数
调用析构函数
通过上面的例子,我们能清楚的看到,第二个对象调用拷贝构造函数,q.f获得的地址值与p.f相同,即指向了同一片内存区域。程序结束时,会两次调用析构函数,即同一个指针执行两遍delete操作,会发生什么呢?这可能是一场灾难,可能会破坏该堆及自由内存表。
那我们该如何避免呢?这里我们就需要使用深拷贝。
#include &iostream&
#include &string&
using namespace
cout && "调用构造函数" &&
f = new char[10];
aa(aa const & s)
cout && "调用拷贝构造函数" &&
f = new char[10];
strcpy(f, s.f);
cout && "调用析构函数" &&
int main(int argc, char **argv)
printf("p.f=%p\n", p.f);
strcpy(p.f, "Computer");
cout && p.f &&
aa q(p);// 调用用戶的拷贝构造函数
printf("q.f=%p\n", q.f);
cout && q.f &&
strcpy(p.f, "Software");
cout && p.f &&
cout && q.f &&
strcpy(q.f, "Software");
cout && p.f &&
cout && q.f &&
运行结果:
调用构造函数
调用拷贝构造函数
调用析构函数
调用析构函数
现在我们可以看到,p.f和q.f分别指向不同的内存区域。
来自:http://blog.csdn.net/sg131971/article/details/7045278标签:&&&&&&&&&&&&&&&&&&&&&&&&&&&原文:/lpxblog/p/4699333.html
教程昨日排行
&&国之画&&&& &&&&&&
&& &&&&&&&&&&&&&&
鲁ICP备号-4
打开技术之扣,分享程序人生!为什么需要拷贝构造函数 - CSDN博客
为什么需要拷贝构造函数
&& & & 也许很多C++的初学者都知道什么是构造函数,但是对复制构造函数(copy constructor)却还很陌生。对于我来说,在写代码的时候能用得上复制构造函数的机会并不多,不过这并不说明复制构造函数没什么用,其实复制构造函数能解决一些我们常常会忽略的问题。
&&&&&&&为了说明复制构造函数作用,我先说说我们在编程时会遇到的一些问题。对于C++中的函数,我们应该很熟悉了,因为平常经常使用;对于类的对象,我们也很熟悉,因为我们也经常写各种各样的类,使用各种各样的对象;对于指针的操作,我们也不陌生吧?嗯,如果你还不了解上面三个概念的话,我想这篇文章不太适合你,不过看看也无碍^_^。我们经常使用函数,传递过各种各样的参数给函数,不过把对象(注意是对象,而不是对象的指针或对象的引用)当作参数传给函数的情况我们应该比较少遇见吧,而且这个对象的构造函数还涉及到一些内存分配的操作。嗯,这样会有什么问题呢?
&&&&&&&把参数传递给函数有三种方法,一种是值传递,一种是传地址,还有一种是传引用。前者与后两者不同的地方在于:当使用值传递的时候,会在函数里面生成传递参数的一个副本,这个副本的内容是按位从原始参数那里复制过来的,两者的内容是相同的。当原始参数是一个类的对象时,它也会产生一个对象的副本,不过在这里要注意。一般对象产生时都会触发构造函数的执行,但是在产生对象的副本时却不会这样,这时执行的是对象的复制构造函数。为什么会这样?嗯,一般的构造函数都是会完成一些成员属性初始化的工作,在对象传递给某一函数之前,对象的一些属性可能已经被改变了,如果在产生对象副本的时候再执行对象的构造函数,那么这个对象的属性又再恢复到原始状态,这并不是我们想要的。所以在产生对象副本的时候,构造函数不会被执行,被执行的是一个默认的构造函数。当函数执行完毕要返回的时候,对象副本会执行析构函数,如果你的析构函数是空的话,就不会发生什么问题,但一般的析构函数都是要完成一些清理工作,如释放指针所指向的内存空间。这时候问题就可能要出现了。假如你在构造函数里面为一个指针变量分配了内存,在析构函数里面释放分配给这个指针所指向的内存空间,那么在把对象传递给函数至函数结束返回这一过程会发生什么事情呢?首先有一个对象的副本产生了,这个副本也有一个指针,它和原始对象的指针是指向同块内存空间的。函数返回时,对象的析构函数被执行了,即释放了对象副本里面指针所指向的内存空间,但是这个内存空间对原始对象还是有用的啊,就程序本身而言,这是一个严重的错误。然而错误还没结束,当原始对象也被销毁的时候,析构函数再次执行,对同一块系统动态分配的内存空间释放两次是一个未知的操作,将会产生严重的错误。
&&&&&&&上面说的就是我们会遇到的问题。解决问题的方法是什么呢?首先我们想到的是不要以传值的方式来传递参数,我们可以用传地址或传引用。没错,这样的确可以避免上面的情况,而且在允许的情况下,传地址或传引用是最好的方法,但这并不适合所有的情况,有时我们不希望在函数里面的一些操作会影响到函数外部的变量。那要怎么办呢?可以利用复制构造函数来解决这一问题。复制构造函数就是在产生对象副本的时候执行的,我们可以定义自己的复制构造函数。在复制构造函数里面我们申请一个新的内存空间来保存构造函数里面的那个指针所指向的内容。这样在执行对象副本的析构函数时,释放的就是复制构造函数里面所申请的那个内存空间。
&&&&&&&除了将对象传递给函数时会存在以上问题,还有一种情况也会存在以上问题,就是当函数返回对象时,会产生一个临时对象,这个临时对象和对象的副本性质差不多。
拷贝构造函数,经常被称作X(X&),是一种特殊的构造函数,他由编译器调用来完成一些基于同一类的其他对象的构件及初始化。它的唯一的一个参数(对象的引用)是不可变的(因为是const型的)。这个函数经常用在函数调用期间于用户定义类型的值传递及返回。拷贝构造函数要调用基类的拷贝构造函数和成员函数。如果可以的话,它将用常量方式调用,另外,也可以用非常量方式调用。&在C++中,下面三种对象需要拷贝的情况。因此,拷贝构造函数将会被调用。&1). 一个对象以值传递的方式传入函数体&2). 一个对象以值传递的方式从函数返回&3). 一个对象需要通过另外一个对象进行初始化&以上的情况需要拷贝构造函数的调用。如果在前两种情况不使用拷贝构造函数的时候,就会导致一个指针指向已经被删除的内存空间。对于第三种情况来说,初始化和赋值的不同含义是构造函数调用的原因。事实上,拷贝构造函数是由普通构造函数和赋值操作赋共同实现的。描述拷贝构造函数和赋值运算符的异同的参考资料有很多。&拷贝构造函数不可以改变它所引用的对象,其原因如下:当一个对象以传递值的方式传一个函数的时候,拷贝构造函数自动的被调用来生成函数中的对象。如果一个对象是被传入自己的拷贝构造函数,它的拷贝构造函数将会被调用来拷贝这个对象这样复制才可以传入它自己的拷贝构造函数,这会导致无限循环。&除了当对象传入函数的时候被隐式调用以外,拷贝构造函数在对象被函数返回的时候也同样的被调用。换句话说,你从函数返回得到的只是对象的一份拷贝。但是同样的,拷贝构造函数被正确的调用了,你不必担心。&如果在类中没有显式的声明一个拷贝构造函数,那么,编译器会私下里为你制定一个函数来进行对象之间的位拷贝(bitwise copy)。这个隐含的拷贝构造函数简单的关联了所有的类成员。许多作者都会提及这个默认的拷贝构造函数。注意到这个隐式的拷贝构造函数和显式声明的拷贝构造函数的不同在于对于成员的关联方式。显式声明的拷贝构造函数关联的只是被实例化的类成员的缺省构造函数除非另外一个构造函数在类初始化或者在构造列表的时候被调用。&拷贝构造函数是程序更加有效率,因为它不用再构造一个对象的时候改变构造函数的参数列表。设计拷贝构造函数是一个良好的风格,即使是编译系统提供的帮助你申请内存默认拷贝构造函数。事实上,默认拷贝构造函数可以应付许多情况。
附另外一篇关于复制构造函数的文章:
对一个简单变量的初始化方法是用一个常量或变量初始化另一个变量,例如:  int m = 80;  int n = m;  我们已经会用构造函数初始化对象,那么我们能不能象简单变量的初始化一样,直接用一个对象来初始化另一个对象呢?答案是肯定的。我们以前面定义的Point类为例:  Point pt1(15, 25);  Point pt2 = pt1;后一个语句也可以写成:  Point pt2( pt1);它是用pt1初始化pt2,此时,pt2各个成员的值与pt1各个成员的值相同,也就是说,pt1各个成员的值被复制到pt2相应的成员当中。在这个初始化过程当中,实际上调用了一个复制构造函数。当我们没有显式定义一个复制构造函数时,编译器会隐式定义一个缺省的复制构造函数,它是一个内联的、公有的成员,它具有下面的原型形式:  Point:: Point (const Point &);可见,复制构造函数与构造函数的不同之处在于形参,前者的形参是Point对象的引用,其功能是将一个对象的每一个成员复制到另一个对象对应的成员当中。  虽然没有必要,我们也可以为Point类显式定义一个复制构造函数:  Point:: Point (const Point &pt)  {   xVal=pt. xV   yVal=pt. yV  }&  如果一个类中有指针成员,使用缺省的复制构造函数初始化对象就会出现问题。为了说明存在的问题,我们假定对象A与对象B是相同的类,有一个指针成员,指向对象C。当用对象B初始化对象A时,缺省的复制构造函数将B中每一个成员的值复制到A的对应的成员当中,但并没有复制对象C。也就是说,对象A和对象B中的指针成员均指向对象C,实际上,我们希望对象C也被复制,得到C的对象副本D。否则,当对象A和B销毁时,会对对象C的内存区重复释放,而导致错误。为了使对象C也被复制,就必须显式定义复制构造函数。下面我们以string类为例说明,如何定义这个复制构造函数。
class String{ public:  String(); //构造函数  String(const String &s); //复制构造函数  ~String(); //析构函数
  // 接口函数  void set(char const *data);  char const *get(void);
 private:  char * //数据成员ptr指向分配的字符串};
String ::String(const String &s){ str = new char[strlen(s.str) + 1]; strcpy(str, s.str);}
我们也常用无名对象初始化另一个对象,例如:  Point pt = Point(10, 20);  类名直接调用构造函数就生成了一个无名对象,上式用左边的无名对象初始化右边的pt对象。  构造函数被调用通常发生在以下三种情况,第一种情况就是我们上面看到的:用一个对象初始化另一个对象时;第二种情况是当对象作函数参数,实参传给形参时;第三种情况是程序运行过程中创建其它临时对象时。下面我们再举一个例子,就第二种情况和第三种情况进行说明:  Point foo(Point pt)&  {&   &&   return   }  void main()  {   Point pt1 = Point(10, 20);   Point pt2;   &   pt2=foo(pt);   &  }  在main函数中调用foo函数时,实参pt传给形参pt,将实参pt复制给形参pt,要调用复制构造函数,当函数foo返回时,要创建一个pt的临时对象,此时也要调用复制构造函数。
缺省的复制构造函数  在类的定义中,如果没有显式定义复制构造函数,C++编译器会自动地定义一个缺省的复制构造函数。下面是使用复制构造函数的一个例子:
#include &iostream.h&#include &string.h&class withCC{ public: withCC(){} withCC(const withCC&) {  cout&&"withCC(withCC&)"&& }};
class woCC{ enum{bsz = 100}; char buf[bsz];public: woCC(const char* msg = 0) {  memset(buf, 0, bsz);  if(msg) strncpy(buf, msg, bsz); } void print(const char* msg = 0)const {  if(msg) cout&&msg&&":";  cout&&buf&& }};
class composite{ withCC WITHCC; woCC WOCC;public: composite() : WOCC("composite()"){} void print(const char* msg = 0) {  WOCC.print(msg); }};
void main(){  c.print("contents of c"); cout&&"calling composite copy-constructor"&& composite c2 = c2.print("contents of c2");}
类withCC有一个复制构造函数,类woCC和类composite都没有显式定义复制构造函数。如果在类中没有显式定义复制构造函数,则编译器将自动地创建一个缺省的构造函数。不过在这种情况下,这个构造函数什么也不作。  类composite既含有withCC类的成员对象又含有woCC类的成员对象,它使用无参的构造函数创建withCC类的对象WITHCC(注意内嵌的对象WOCC的初始化方法)。  在main()函数中,语句:  composite c2 =通过对象C初始化对象c2,缺省的复制构造函数被调用。  最好的方法是创建自己的复制构造函数而不要指望编译器创建,这样就能保证程序在我们自己的控制之下。
本文已收录于以下专栏:
相关文章推荐
在数理统计学中,似然函数是一种关于统计模型中的参数的函数,表示模型参数中的似然性。“似然性”与“或然性”或“概率”意思相近,都是指某种事件发生的可能性,但是在统计学中,“似然性”和“或然性”或“概率”...
最小二乘法
简单地说,最小二乘的思想就是要使得观测点和估计点的距离的平方和达到最小.这里的“二乘”指的是用平方来度量观测点与估计点的远近(在古汉语中“平方”称为“二乘”),“最小”指...
总结了线性回归的理论部分,厦门
最大似然估计学习总结------MadTurtle
在已知试验结果(即是样本)的情况下,用来估计满足这些样本分布的参数,把可能性最大的那个参数作为真实的参数估计。
最大后验估计是根据经验数据获得对难以观察的量的点估计。与最大似然估计类似,但是最大的不同时,最大后验估计的融入了要估计量的先验分布在其中。故最大后验估计可以看做规则化的最大似然估计。
    首先,...
极大似然估计,顾名思义是一种估计方法
在开始接触最大似然估计和贝叶斯估计时,大家都会有个疑问:最大似然估计和贝叶斯估计二者很相似,到底有何区别?本文便来说说二者的不同之处以及推导二者使用时的数学模型!预热知识必知如何求类条件概率密度:
机器学习算法与Python实践之(一)k近邻(KNN)http://blog.csdn.net/zouxy09        机器学习算法与Python实践这个系列主要是参...
极大似然估计
        以前多次接触过极大似然估计,但一直都不太明白到底什么原理,最近在看贝叶斯分类,对极大似然估计有了新的认识,总结如下:
贝叶斯决策
        首先来看贝叶斯分类,...
他的最新文章
讲师:吴岸城
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)cpp编程笔记(9)
我们在制定类的对象拷贝、移动、赋值和销毁时,一般会使用下面五中特殊的成员函数来定义:
拷贝构造函数 (copy constructor)
拷贝赋值运算符 (copy-assignment perator)
移动构造函数 (move constructor)
移动赋值运算符(move-assignment operator)
析构函数(destructor)
以上的这些操作被称为:拷贝控制操作(copy control)
若一个类没有自定义这写拷贝控制成员编译器会自动为它定义所缺失的操作,但是对于有些类而言,使用编译器所定义的默认操作常常会导致灾难!!!
拷贝构造函数
认识: 第一个参数是自身类类型的引用,切任何额外参数都有默认值的构造函数。
【问】:为何第一个参数必须是引用 ?
【原因】: 函数调用过程中,具有非引用类型的参数要进行拷贝初始化,若拷贝构造函数不是引用类型的参数,则会调用该类类型的拷贝构造函数进行拷贝初始化,则会无限调用下去。
合成拷贝构造函数
若我们没有为一个类定义拷贝构函数,无论我们是否定义了其他构造函数(与合成默认构造函数不同点),只要不存在自定义拷贝构造函数,编译器会为我们定义一个,称为合成拷贝构造函数。
合成拷贝构造函数的作用:
(1)阻止我们拷贝该类类型的对象;
(2)将其参数的成员逐个拷贝到正在创建的对象中。
合成拷贝函数的拷贝过程:
(1)类类型的成员将调用其拷贝构造函数;
(2)内置类型的成员则直接拷贝;
(3)逐一拷贝数组类型的成员。
可以说,每个成员的类型决定了它们的拷贝方式。
直接初始化与拷贝初始化:
string dots(10,',');
string s(dots);
string s2 =
string null_book = "9--9";
string nines = string(100,'9');
直接初始化:要求编译器使用普通的函数匹配来选择与我们提供参数最匹配的构造函数;
拷贝初始化:要求编译器将右侧运算对象拷贝到正在创建的对象中,还会进行类型转换,通常使用拷贝构造函数来完成。(例外,优先使用移动构造函数)
拷贝初始化另外的情况:
将一个对象作为实参传递给一个非引用的类型的形参;
从一个返回类型为非引用类型的函数返回一个对象;
花括号列表初始化一个数组中的元素或一个聚合类(struct)中的成员。
一个explicit修饰的构造函数,不能隐式地被调用。
拷贝赋值运算符
赋值运算符为一个成员函数;通过对赋值运算符的重载控制其对象如何赋值。
合成拷贝赋值运算:类似于合成拷贝构造函数,可以用来禁止该类型对象的赋值;除外一般情况为将右侧运算对象的每个非static成员赋予左侧运算对象的对应成员。
【认识】析构函数执行与构造函数相反的操作:
(1)构造函数初始化对象的非static数据成员,附带做一些其他工作;
(2)析构函数释放对象所使用的资源,并销毁对象的非static数据成员。
调用析构函数的情况:一个对象被销毁时都会调用析构函数。
(1)变量离开作用域时被销毁;
(2)当一个对象被销毁时,其成员被销毁;
(3)容器被销毁时;
(4)动态分配的对象,当对指向它的指针应用delete运算符时被销毁;
(5)对于临时对象,当创建它的完整表达式结束时被销毁。
合成析构函数:一个类未自定义自己的析构函数时,编译器会自动为其合成一个析构函数-合成析构函数。其作用被用来阻止该类型的对象呗销毁。除此之外,合成析构函数的函数体为空!
一个类需要自定义拷贝控制操作的情况:
(1)三个操作通常被看做一个整体,一般应该全部定义
(2)需要析构函数的类也需要拷贝和赋值操作
(3)需要拷贝操作的类也需要赋值操作
阻止拷贝操作
【认识】对于大多数的类,都需要拷贝构造函数和拷贝赋值运算符,但还有一些类,并不需要这些拷贝操作,甚至拷贝操作是被禁止的。因此我们在定义类中,可以采用某种机制阻止拷贝或赋值。
机制一:新标准中delete关键字使用
struct NoCopy{
NoCopy() = default;
NoCopy(const NoCopy&) = delete;
NoCopy& operator=(const NoCopy&)
~NoCopy()= default;
使用delete注意:不能对析构函数使用delete,否则会无法销毁次类型的对象了。
机制二:private关键字修饰拷贝控制
class PrivateCopy{
PrivateCopy() = default;
~PrivateCopy();
PrivateCopy(const PrivateCopy&);
PrivateCopy& operator= (const PrivateCopy&);
移动构造函数(待补充)
移动赋值运算符(待补充)
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:3739次
排名:千里之外
原创:21篇
(1)(1)(4)(2)(9)(4)(1)
(window.slotbydup = window.slotbydup || []).push({
id: '4740887',
container: s,
size: '250,250',
display: 'inlay-fix'

我要回帖

更多关于 拷贝构造函数 的文章

 

随机推荐