C++ Copy Constructor in depth (深入理解C++拷贝构造函数)

The copy constructor is a special kind of constructor which creates a new object which is a copy of an existing one, and does it efficiently.

(拷贝构造函数是一种特别的构造函数,用于复制已经存在的对象到新生成的对象,这是一种高效的方式。)

Here below is a simple declaration of a copy constructor:

(下面是拷贝构造函数简单的声明:)

class string
{
    string();
    ~string();
    string(const string &s)
    {
        copy(s.m_str);
    }
};

Now you can use it as follow:

(现在,你可以按照下面的方式使用拷贝构造函数)

// create an object which is copy of another object
string s1("hello");
string s2(s1);   // copy constructor activated
// create an object as a copy of a temporary object
string s3(string("abc"));
string s4 = s1;
// object s4 does not activate the constructor, but its copy constructor to make only a copy of s1, rather than building a new object

you have to use const in the argument at the copy constructor to create an object as a copy of a temporary object: e.g. string(const string &s).

(在拷贝构造函数中,你必须使用const关键字作为参数)

to make things clear, you can create a new object as copy of a different object without using a copy constructor, like this:

(进一步将,你可以不使用拷贝构造函数来复制一个对象到另一个新对象)

string s4;
s4.set(s1);

this is an example of inefficient code. Since s4 first call its constructor to build a new object and then it make a bit-wise copy of s1. The whole process of calling the constructor to build an object which next is being rewritten, is wasteful, takes time and resources. Copy constructor allow you to prevents this inefficiency.

(这是一个效率低下的代码。由于s4首先需要调用自己的构造函数创建一个对象,然后把s1按位拷贝到s4.整个处理的过程是调用构造函数创建一个对象,然后重写这个对象,这是一种浪费时间、浪费资源的做法。拷贝构造函数可以帮你预防这种低效。)

Default copy constructor

If the programmer did not declared the copy constructor for a class, the compiler will add its own default copy constructor for the objects derived from that class.

Default copy constructor does a very simple operation, they will do a bit-wise (member-wise) copy of an object, which means that the object will be copied bit by bit.

(如果程序员没有提供拷贝构造函数,那么编译器会自动生成默认的拷贝构造函数。默认的拷贝构造函数会执行简单的操作,即按位拷贝对象。)

string s1("hello");
string s2(s1);
string s2 = s1; //the same as above

There is a danger in copying an object bit by bit, if the object contains pointers since the pointer address will be copied in the process resulting in two different objects that share the same memory buffer. You can imagine what will happen when two copies of an object calls their destructors one after the other. The first object that call its destructor will have no problems, since it will try to deallocate the pointer and succeed, but the second objects destructor try to deallocate a pointer which does not exist anymore and the whole application crashes!

(如果对象中含有指针,那么按位拷贝就是很危险的。是因为两个对象的指针会指向同一片内存。你可以想象一下,当两个拷贝的对象去调用他们的析构函数的时候会发生什么。首先调用析构函数的对象不会有任何问题,但是第二个对象的析构函数就会尝试去释放不存在的资源,这样会道是整个应用程序的崩溃。)

For a situation where an object contain pointers we have to write our own copy constructor that will prevent situations like those mentioned above.

(对于类对象包含指针的情况下,我们要编写自己的拷贝构造函数,这样可以防止上述情况的发生)

There are 3 situations in which the copy constructor is called:

When we make copy of an object.

When we pass an object as an argument by value to a method.

When we return an object from a method by value.

(有三种情况下拷贝构造函数会被调用:

当拷贝对象时候

当按值传递一个对象作为方法参数的时候

当按值返回一个对象时候)

we saw the first scenario above, and we will now look at the other two scenarios.

(我们已经在上述中展示了第一种情况,下面我将会带领大家看看后两种情况。)

When objects are passed to a function as arguments by value, a bit wise copy of the object will be passed to the function and placed on the stack, therefor the constructor of the object will not be called. It make sense if you think of it, you want to pass an object in a certain state containing the data you need for the function to process, if you wanted it in the initialization state with its default data, you could just create it inside the function instead of passing it as an argument.

(当一个对象按值传递给一个函数作为参数,对象将会按位拷贝到函数中,并且置于栈中。所以此时对象的构造函数不会被 调用。当你希望传递的对象有初始化值的时候,你应该在函数的内部创建它来代替作为参数传给函数。)

When the function end, the constructor of the object will be called. This is also make sense since the object was passed by value and its data will not be needed outside the function scope.

(当函数结束的时候,对象的析构函数就会被调用。这似乎也很合理,因为我们是按值进行的传递,在超出函数的作用范围后,我们不需要该变量。)

No pay attention to this, the situation in which only the object destructor is called can make great deal of troubles. Think what will happen when the object holds a pointer to some address in the memory. When this object is passed as argument to a function the pointer in the new temporary created object will hold the same address as the original object, since its a bit wise copy. When the function ends, the destructor will free the address pointed by the pointer. From this point, if the destructor of the original object will be called it will try to free an address which already free, and we all know what it the consequences of that …

(没有注意到的是,对象的析构函数调用后会引起很大的麻烦。想想如果对象中包含了指向地址的指针会发生什么。由于是按位拷贝,当传递一个对象给函数作为参数的时候,新产生的临时性的对象的指针将会与 原来对象的指针指向同一个地址。当函数结束的时候,析构函数将会释放指针指向的地址。从这点来看,如果原来对象 的析构函数被调用,它将会释放已经释放的内存,我们都知道会发生什么样的后果。)

lets look at an example to make things clear.

Here we define string class which holds a char* pointer:

(让我们看看下面的例子,以便更加清楚 这里我们定义的string类包含了一个char*指针)

class string
{
    // constructor
    string(char* aStr)
    {
        str = new char[sizeof(aStr)];
        strcpy (str,aStr);
    }
    // destructor
    ~string()
    {
        del str;
    }
    char *getChars(){ return str; }
    char* str;
};

now we will write a function that receive a string object as an argument.

(现在,我们写一个接受string对象作为参数的函数:)

void function (string str)
{
// do somthing
}

Lets look what will happen when we call this function :

(当我们调用这个函数的时候看看会发生什么:)

void main ()
{
    string str("hello");
    function(str);
    function(str); // program crush
}

The first time we call function(str) everything works properly, when the function ends, the input argument on the stack is destroyed, and its destructor will be called, and delete the pointer.

The second time we call the function , everything still works properly, but when the function ends, the constructor will try now to free the address pointed by str, and crash.

(第一次调用function函数的时候一切都很正常,当函数结束的时候,栈上的参数会被销毁,所以对象的析构函数会被调用,并且删除指针指向的内容。 第二次调用function函数的时候,一切似乎同样正常。但当函数结束的时候,析构函数会试图去释放指针str指向地址的内容,这样就会造成奔溃。)

The copy constructor come to help us solve this kind of problems. Here is a solution:

(拷贝构造函数会帮助我们解决这样的问题,下面是解决方法:)

class string
{
    // constructor
    string(char* aStr)
    {
        str = new char[sizeof(aStr)];
        strcpy (str,aStr);
    }
    string(string &strObj)
    {
        tmpStr = strObj.getChars();
        str = new tmpStr[sizeof(tmpStr)];
        strcpy (str,tmpStr);
    }
    // destructor
    ~string()
    {
        del str;
    }
    char* str;
};

The same way we can handle the third scenario where a method returns an object:

(同样的方式,我们演示了上诉的第三种情况,即返回一个对象)

class string
{
    public:
    string(char* aStr)
    {
        str = new char[ strlen(aStr) + 1 ];
        strcpy (str,aStr);
    }
    string(string &strObj)
    {
        str = new char[ strObj.str ];
        strcpy( str, strObj.str );
    }
    string &string::operator=(const string &s)
    {
        string temp( s );
        std::swap( temp.str, str );
        return *this;
    }
    // destructor
    ~string()
    {
        delete[] str;
    }
    private:
    char* str;
};
时间: 2024-10-22 00:44:42

C++ Copy Constructor in depth (深入理解C++拷贝构造函数)的相关文章

一道笔试题的理解C++拷贝构造函数

看下面代码输出 #include <iostream> #include <string.h> #include <stdio.h> class A{ char* data; public: A(char* pdata){ int len = strlen(pdata); data = new char[len+1]; memset(data, 0, len+1); memcpy(data, pdata, len); printf("just call me\

Copy constructor拷贝构造函数

翻译的是wikipedia关于copy constructor,地址:点击打开链接 拷贝构造函数是C++语言中用一个已有对象创建一个新对象的特殊构造函数,该函数的第一个参数必须是函数所在类型的引用(译注:const/non-const都可以,可以有多个参数剩余参数必须有默认值,一定要是引用,这些原因见后,问:有多个参数拷贝构造如何调用?). 通常编译器会自动为每一个class创建一个拷贝构造函数(显示拷贝构造);有些情况下程序员自定义了拷贝构造函数(用户自定义拷贝构造),这时编译器不合成拷贝构造

类的三个特殊成员Copy Constructor、Copy-Assignment Operator、Destructor重载与使用

今天看<C++ Primer>的13.1节--Copy, Assign, and Destroy 被这几个玩意儿弄得晕得不行: ◆   Copy Constructor ◆   The Copy-Assignment Operator ◆   Destructor 主要问题集中在: ◆   我们在什么时候需要自己重写? ◆   系统会在什么时候用我们重写的版本? ◆   拷贝构造和赋值操作符的区分到底是什么? 0x00 特性 为了区分他们,我们首先要分别从每一个的特性说起 这个可以参考 htt

Copy Constructor in Java

Reference: TutorialPoints, GeekforGeeks The copy constructor is a constructor which creates an object by initializing it with an object of the same class, which has been created previously. The copy constructor is used to: Initialize one object from

[C++] Deep copy ,Shallow copy, copy constructor,&quot;=&quot;

Deep copy ,Shallow copy, copy constructor,"=" Dog.h #pragma once class Dog { public: char *name; Dog(); Dog(const Dog &it); ~Dog(); void operator =(const Dog &it); }; Dog.cpp #include "Dog.h" #include<string.h> #include&l

C++对象模型——Copy Constructor 的建构操作(第二章)

2.2    Copy Constructor 的建构操作 有三种情况,会以一个object的内容作为另一个 class object的初值,最明显的一种情况就是对一个object做显式的初始化操作,例如: class X { ... }; X x; // 明确地以一个object的内容作为另一个class object的初值 X xx = x; 另两种情况是当object被当作参数交给某个函数时,例如 extern void foo(X x); void bar() { X xx; // 以x

no copy constructor available or copy constructor is declared &amp;#39;explicit&amp;#39;

今天新写了一个类.然后对这个类使用STL中的vector,碰到错误: no copy constructor available or copy constructor is declared 'explicit' 假设碰到同样错误.能够检查一下重载的拷贝构造函数以及重载的'='运算符函数是否有问题,注意输入的參数必须是const类型的,少了constkeyword不行. no copy constructor available or copy constructor is declared

深入探索c++对象模型-&gt;2.2 Copy Constructor的构造操作

一.只有当class不展现出bitwise copy semanties时,编译器才会为class生成copy constructor.那么当什么时候回出现非bitwise copy呢? 1.当class内含一个member object而后者的class声明有一个copy constructor时(不论是显示声明或是被合成得到的): 2.当class继承自一个base class而后者存在一个copy constructor时. 3.当class声明了一个或多个virtual function

copy constructor

copy constructor也分为trivial和nontrivial两种 如果class展现出bitwise copy semantics(按位拷贝语义),则不会构造出 copy constructor. 反之,会构造出一个copy constructor. 不要bitwise copy semantics 内含一个拥有nontrivial copy constructor的成员变量 base class 存在一个nontrivial copy constructor virtual fu