代码之家  ›  专栏  ›  技术社区  ›  fredoverflow

三个规则是什么?

  •  1989
  • fredoverflow  · 技术社区  · 15 年前
    • 什么? 复制对象 意思是?
    • 什么是 复制构造函数 以及 复制分配运算符 ?
    • 我什么时候需要自己申报?
    • 如何防止复制对象?
    8 回复  |  直到 7 年前
        1
  •  1636
  •   JVApen    7 年前

    class person
    {
        std::string name;
        int age;
    
    public:
    
        person(const std::string& name, int age) : name(name), age(age)
        {
        }
    };
    
    int main()
    {
        person a("Bjarne Stroustrup", 60);
        person b(a);   // What happens here?
        b = a;         // And here?
    }
    

    name(name), age(age) member initializer list

    person main person b(a); b = a

    // 1. copy constructor
    person(const person& that) : name(that.name), age(that.age)
    {
    }
    
    // 2. copy assignment operator
    person& operator=(const person& that)
    {
        name = that.name;
        age = that.age;
        return *this;
    }
    
    // 3. destructor
    ~person()
    {
    }
    

    name age

    std::string

    class person
    {
        char* name;
        int age;
    
    public:
    
        // the constructor acquires a resource:
        // in this case, dynamic memory obtained via new[]
        person(const char* the_name, int the_age)
        {
            name = new char[strlen(the_name) + 1];
            strcpy(name, the_name);
            age = the_age;
        }
    
        // the destructor must release this resource via delete[]
        ~person()
        {
            delete[] name;
        }
    };
    

    1. a b
    2. a.name
    3. undefined behavior

    // 1. copy constructor
    person(const person& that)
    {
        name = new char[strlen(that.name) + 1];
        strcpy(name, that.name);
        age = that.age;
    }
    
    // 2. copy assignment operator
    person& operator=(const person& that)
    {
        if (this != &that)
        {
            delete[] name;
            // This is a dangerous point in the flow of execution!
            // We have temporarily invalidated the class invariants,
            // and the next statement might throw an exception,
            // leaving the object in an invalid state :(
            name = new char[strlen(that.name) + 1];
            strcpy(name, that.name);
            age = that.age;
        }
        return *this;
    }
    

    x = x delete[] name this->name that.name

    new char[...]

    // 2. copy assignment operator
    person& operator=(const person& that)
    {
        char* local_name = new char[strlen(that.name) + 1];
        // If the above statement throws,
        // the object is still in the same state as before.
        // None of the following statements will throw an exception :)
        strcpy(local_name, that.name);
        delete[] name;
        name = local_name;
        age = that.age;
        return *this;
    }
    

    copy-and-swap idiom

    private

    private:
    
        person(const person& that);
        person& operator=(const person& that);
    

    boost::noncopyable

    person(const person& that) = delete;
    person& operator=(const person& that) = delete;
    

    class person
    {
        std::string name;
        int age;
    
    public:
        person(const std::string& name, int age);        // Ctor
        person(const person &) = default;                // Copy Ctor
        person(person &&) noexcept = default;            // Move Ctor
        person& operator=(const person &) = default;     // Copy Assignment
        person& operator=(person &&) noexcept = default; // Move Assignment
        ~person() noexcept = default;                    // Dtor
    };
    

    char*

        2
  •  473
  •   Community Mohan Dere    9 年前
        3
  •  149
  •   rmobis ceejayoz    8 年前

        4
  •  41
  •   Shakti Malik    10 年前

        MyClass x(a, b);
        MyClass y(c, d);
        x = y; // This is a shallow copy if assignment operator is not provided
    

        5
  •  34
  •   David Szalai user1701047    12 年前

    class Car //A very simple class just to demonstrate what these definitions mean.
    //It's pseudocode C++/Javaish, I assume strings do not need to be allocated.
    {
    private String sPrintColor;
    private String sModel;
    private String sMake;
    
    public changePaint(String newColor)
    {
       this.sPrintColor = newColor;
    }
    
    public Car(String model, String make, String color) //Constructor
    {
       this.sPrintColor = color;
       this.sModel = model;
       this.sMake = make;
    }
    
    public ~Car() //Destructor
    {
    //Because we did not create any custom types, we aren't adding more code.
    //Anytime your object goes out of scope / program collects garbage / etc. this guy gets called + all other related destructors.
    //Since we did not use anything but strings, we have nothing additional to handle.
    //The assumption is being made that the 3 strings will be handled by string's destructor and that it is being called automatically--if this were not the case you would need to do it here.
    }
    
    public Car(const Car &other) // Copy Constructor
    {
       this.sPrintColor = other.sPrintColor;
       this.sModel = other.sModel;
       this.sMake = other.sMake;
    }
    public Car &operator =(const Car &other) // Assignment Operator
    {
       if(this != &other)
       {
          this.sPrintColor = other.sPrintColor;
          this.sModel = other.sModel;
          this.sMake = other.sMake;
       }
       return *this;
    }
    
    }
    

    Car car1 = new Car("mustang", "ford", "red");
    Car car2 = car1; //Call the copy constructor
    car2.changePaint("green");
    //car2 is now green but car1 is still red.
    

    //Shallow copy example
    //Assume we're in C++ because it's standard behavior is to shallow copy objects if you do not have a constructor written for an operation.
    //Now let's assume I do not have any code for the assignment or copy operations like I do above...with those now gone, C++ will use the default.
    
     Car car1 = new Car("ford", "mustang", "red"); 
     Car car2 = car1; 
     car2.changePaint("green");//car1 is also now green 
     delete car2;/*I get rid of my car which is also really your car...I told C++ to resolve 
     the address of where car2 exists and delete the memory...which is also
     the memory associated with your car.*/
     car1.changePaint("red");/*program will likely crash because this area is
     no longer allocated to the program.*/
    

    Car car2 = car1; car2 = car1; car2

        6
  •  23
  •   Ajay yadav    10 年前

    • 管理内存(例如,执行动态内存管理的STL容器)都声明“三大”:复制操作和析构函数。

    三法则的结果 是否存在用户声明的析构函数表示简单的成员级复制不太可能适用于类中的复制操作。反过来,这意味着如果一个类声明了一个析构函数,那么复制操作可能不应该自动生成,因为它们不会做正确的事情。在采用C++ 98时,这条推理线的意义没有得到充分的理解,因此在C++ 98中,用户声明的析构函数的存在对编译器产生复制操作的意愿没有影响。在C++ 11中,情况仍然如此,但仅仅因为限制生成复制操作的条件会破坏太多的遗留代码。

    如何防止复制对象?

    将复制构造函数和复制分配运算符声明为私有访问说明符。

    class MemoryBlock
    {
    public:
    
    //code here
    
    private:
    MemoryBlock(const MemoryBlock& other)
    {
       cout<<"copy constructor"<<endl;
    }
    
    // Copy assignment operator.
    MemoryBlock& operator=(const MemoryBlock& other)
    {
     return *this;
    }
    };
    
    int main()
    {
       MemoryBlock a;
       MemoryBlock b(a);
    }
    

    在C++ 11中,您还可以声明复制构造函数和赋值操作符被删除。

    class MemoryBlock
    {
    public:
    MemoryBlock(const MemoryBlock& other) = delete
    
    // Copy assignment operator.
    MemoryBlock& operator=(const MemoryBlock& other) =delete
    };
    
    
    int main()
    {
       MemoryBlock a;
       MemoryBlock b(a);
    }
    
        7
  •  14
  •   xyz    11 年前

    许多现有的答案已经接触到复制构造函数、赋值运算符和析构函数。 然而,在后C++ 11中,移动语义的引入可能会扩展到3以上。

    最近,Michael Claisse做了一个关于这个主题的演讲: http://channel9.msdn.com/events/CPP/C-PP-Con-2014/The-Canonical-Class

        8
  •  9
  •   ReinstateMonica3167040 urvashi bhagat    9 年前

    C++中的三条规则是设计的基本原则和三个要求的发展,如果在下列成员函数中有一个明确的定义,那么程序员应该一起定义其他两个成员函数。也就是说,以下三个成员函数是必不可少的:析构函数、复制构造函数、复制赋值运算符。

    C++中的复制构造函数是一种特殊的构造函数。它用于构建一个新对象,这个新对象相当于一个现有对象的副本。

    // default constructor
    My_Class a;
    
    // copy constructor
    My_Class b(a);
    
    // copy constructor
    My_Class c = a;
    
    // copy assignment operator
    b = a;
    
    推荐文章