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

从运算符的角度实现复制构造函数=

  •  18
  • gregseth  · 技术社区  · 15 年前

    如果 operator= 定义正确,是否可以将以下内容用作复制构造函数?

    MyClass::MyClass(MyClass const &_copy)
    {
        *this = _copy;
    }
    
    8 回复  |  直到 11 年前
        1
  •  27
  •   Alexandre C.    15 年前

    如果所有成员 MyClass 有一个默认的构造函数,是的。

    注意,通常情况下是相反的:

    class MyClass
    {
    public:
        MyClass(MyClass const&);     // Implemented
        void swap(MyClass&) throw(); // Implemented
        MyClass& operator=(MyClass rhs) { rhs.swap(*this); return *this; }
    };
    

    我们通过价值 operator= 以便调用复制构造函数。注意,一切都是异常安全的,因为 swap 保证不会抛出(您必须在实现中确保这一点)。

    根据要求,编辑有关按值呼叫的内容: 运算符= 可以写为

    MyClass& MyClass::operator=(MyClass const& rhs)
    {
        MyClass tmp(rhs);
        tmp.swap(*this);
        return *this;
    }
    

    C++学生通常被告知通过引用传递类实例,因为复制构造函数是通过值传递的调用。在我们的情况下,我们必须复制 rhs 不管怎样,传递值是可以的。

    因此, 运算符= (第一版,按值调用)显示:

    • 复印一份 RHS (通过复制构造函数,自动调用)
    • 将其内容与交换 *this
    • 返回 *此 RHS (包含旧值)在方法出口销毁。

    现在,我们有一个额外的奖金与这个电话按价值。如果要传递给的对象 运算符= (或任何按值获取参数的函数)是 临时对象 编译器可以(通常也可以)不进行任何复制。这叫做 复制省略 .

    因此,如果 RHS 是临时的,不复制。我们只剩下:

    • 掉期 this RHS 内容
    • 破坏 RHS

    所以在这种情况下传递值是 更多 比通过引用有效。

        2
  •  11
  •   Steve Townsend    15 年前

    对于异常安全复制构造函数,更建议实现operator=参见示例4。在这篇文章中,赫伯萨特解释了这项技术,以及为什么这是一个好主意。

    http://www.gotw.ca/gotw/059.htm

        3
  •  5
  •   Cătălin Pitiș    15 年前

    此实现意味着所有数据成员(和基类)的默认构造函数都是可用的,并且可以从MyClass访问,因为在进行分配之前,将首先调用它们。即使在这种情况下,对构造函数进行这种额外的调用也可能很昂贵(取决于类的内容)。

    我仍然坚持通过初始化列表分离复制构造函数的实现,即使这意味着要编写更多的代码。

    另一件事:这个实现可能有副作用(例如,如果您动态分配了成员)。

        4
  •  1
  •   xtofl Adam Rosenfield    15 年前

    虽然最终结果相同,但成员首先是默认初始化的,之后才复制。

    对于“昂贵”成员,您最好使用初始值设定项列表复制构造。

    struct C {
       ExpensiveType member;
    
       C( const C& other ): member(other.member) {}
    };
    
    
    
     };
    
        5
  •  0
  •   duffymo    15 年前

    我会说如果 MyClass 分配内存或可变。

        6
  •  0
  •   timB33    15 年前

    对。

    就个人而言,如果你的类没有指针,尽管我不会重载equal运算符或编写copy构造函数,让编译器为你做这些;它将实现一个浅显的副本,你将确定所有成员数据都被复制,而如果你重载了=op;然后添加一个数据成员,然后忘记更新重载yo你会有麻烦的。

        7
  •  0
  •   Manoj R    15 年前

    @Alexandre-我不确定是否在赋值运算符中传递值。在那里调用复制构造函数有什么好处?这会固定分配操作员吗?

    另外,我不知道怎么写评论。或者可能是我不允许写评论。

        8
  •  0
  •   Martin Ba    14 年前

    技术上可以,如果你有一个工作分配操作符(复制操作符)。

    但是,您应该更喜欢复制和交换,因为:

    • 使用副本交换更容易实现例外安全性
    • 最合理的关注分离 :
      • 复制系数是关于 分配 它需要的资源(复制其他东西)。
      • 交换函数主要是 只有 关于交换内部“句柄”,不需要进行资源(de)分配
      • 析构函数是关于资源释放的
      • 复制和交换在赋值/复制操作符中自然地结合了这三个函数