关于C++拷贝构造函数有什么大惊小怪的?

bod*_*ydo 15 c++ copy-constructor

可能重复:
我们何时必须使用复制构造函数?

为什么C++拷贝构造函数如此重要?我刚刚了解了它们,我不太清楚它们是什么.如果你使用指针,你似乎应该总是为你的类编写一个复制构造函数,但为什么呢?

谢谢,Boda Cydo.

650*_*502 29

复制构造函数和赋值运算符在C++中非常重要,因为该语言具有"复制语义",也就是说当您传递参数或在容器中存储值时,传递或存储对象的副本.C++如何在对象上复制或执行赋值?对于本机类型,它本身就知道,但对于用户定义的类型,它会自动生成逐个成员的副本构造或赋值.

如果您声明为例,则更明确:

class P2d
{
    public:
        double x, y;
        P2d(double x, double y) : x(x), y(y)
        { }
};
Run Code Online (Sandbox Code Playgroud)

C++编译器自动完成您的代码

class P2d
{
    public:
        double x, y;
        P2d(double x, double y) : x(x), y(y)
        { }

        P2d(const P2d& other) : x(other.x), y(other.y)
        { }

        P2d& operator=(const P2d& other)
        {
            x = other.x;
            y = other.y;
            return *this;
        }
};
Run Code Online (Sandbox Code Playgroud)

这些自动生成的复制构造函数和赋值运算符是否适合您的类?在许多情况下是的...但当然可能这些实现完全错误.例如,当您在对象中包含指针时,只需要在复制对象时复制指针就不是正确的事情.

您必须了解C++会执行大量对象副本,并且您必须了解它将为您定义的类执行哪种类型的副本.如果自动生成的副本不是您需要的,那么您必须提供自己的实现,或者必须告诉编译器您的类应该禁止复制.

您可以通过声明私有拷贝构造函数和赋值运算符以及不提供实现来阻止编译器进行复制.因为那些是私有函数,任何将要使用它们的外部代码都会出现编译错误,并且因为你声明了它们但你没有实现它们,如果你错误地最终在类中生成副本,你会得到一个链接错误实现.

例如:

class Window
{
    public:
        WindowType t;
        Window *parent,
               *prev_in_parent, *next_in_parent,
               *first_children, *last_children;
        Window(Window *parent, WindowType t);
        ~Window();

    private:
        // TABOO! - declared but not implemented
        Window(const Window&); // = delete in C++11
        Window& operator=(const Window&); // = delete in C++11
};
Run Code Online (Sandbox Code Playgroud)

如果最后一部分看起来很荒谬(你怎么能错误地在实现中复制)请注意,在C++中,错误地制作额外的副本非常容易,因为语言是围绕复制事物的概念构建的.

金色的规则是,如果你的类有析构函数(因为它需要做一些清理工作),那么最有可能的一个成员,由成员副本不是做正确的事......而且,如果你有特殊的逻辑做一个复制构造然后在分配中也可能需要类似的逻辑(反之亦然).因此,称为三巨头的规则指出,您的类没有自定义析构函数,没有复制构造函数,没有赋值运算符,或者您的类应该包含所有这三个.

这条规则是非常重要的,例如如果你结束了,只是需要一个析构函数类的任何特殊情况下(我想不出一个合理的情况......但我们只能说,你找到了一个),那么请记得添加为你想到它的评论,你知道隐式生成的复制构造函数和赋值运算符是可以的.如果你没有添加关于其他两个的注释,那么阅读你的代码的人会认为你只是忘记了它们.

UPDATE

C++正在发展,虽然这里所说的大部分内容仍然有效,但现在语言提供了一种更好的方法来通知编译器不应该允许复制和赋值.

新语法(自C++ 11起有效)是

struct Window {
    ...
    Window(const Window&) = delete;
    Window& operator=(const Window&) = delete;
};
Run Code Online (Sandbox Code Playgroud)

  • 我从未见过他们被称为"三个朋友",总是被称为"三巨头".人们称之为Booch,Jacobson和Rumbaugh,UML的创始人. (4认同)

Owe*_* S. 7

简单:当C++使用默认的复制构造函数时,它会复制指针,但不会复制指向的数据.结果:两个对象指向相同的数据.如果都认为他们自己的数据,并删除它们时调用析构函数指针,你有一堆的麻烦......


dan*_*n04 6

为什么C++拷贝构造函数如此重要?

大多数其他语言不需要复制构造函数,因为它们可以:

  • 没有指针(例如旧版本的BASIC),在这种情况下复制对象总是安全的,或者
  • 什么都没有,但指针/引用(例如,使用Java,Python),在这种情况下复制是罕见的,然后可以用做copy()clone()方法.

C++更喜欢值语义,但也使用了很多指针,这意味着:

  • 对象被复制很多,并且
  • 由于其他人提到的原因,您必须指定是要还是浅版还是深版.