Calling assignment operator in copy constructor
这种复制构造函数的实现有什么缺点吗?
1 2 3 4
| Foo::Foo(const Foo& i_foo)
{
*this = i_foo;
} |
我记得,在一些书中建议从赋值操作符调用复制构造函数并使用众所周知的交换技巧,但我不记得为什么……
- stackoverflow.com/questions/1533725/…的可能副本
- 另一个副本:stackoverflow.com/questions/1457842/…related:stackoverflow.com/questions/1477145/…stackoverflow.com/questions/1734628/…stackoverflow.com/questions/2034635/…
- 那是哪本书?调用公共代码(可能在命名的私有函数中)来执行复制是一个好的实践。但是要使用赋值运算符形式的复制构造函数吗?在大多数情况下-不。
是的,那是个坏主意。用户定义类型的所有成员变量将首先初始化,然后立即覆盖。
交换技巧是:
1 2 3 4 5
| Foo& operator=(Foo rhs) // note the copying
{
rhs.swap(*this); //swap our internals with the copy of rhs
return *this;
} // rhs, now containing our old internals, will be deleted |
- "这是一个坏主意,"在我看来,这个说法太过宽泛了。这么说,你可能是过早的微观优化。如果您同时在ctor和op=()中编写分配代码,则会创建重复的代码并违反dry。找出双重初始化所涉及的成本,将其与降低代码库复杂性所带来的好处进行比较,然后确定哪种方法是正确的。
- 交换技巧的好处在于它自动处理自分配,并且(假设.swap()不抛出)是强异常安全的,因为要么分配成功,要么保持不变,并抛出异常。
- 除了现在,通过按值传递rhs可以更好地完成这个技巧。参见cpp-next.com/archive/2009/08/want-speed-pass-by-value
- @卡兹:你说得对。这两天我不得不承认我做的事情主要是出于旧习惯,而不是为什么它(仍然)被认为是最先进的。也许我老了。
- @从copy ctor调用op=(johndibling)并不是避免代码重复的唯一方法,我认为在所有的技术中,它仍然不是一个很好的方法。
- foo是抽象类怎么样?
- @卡米诺:那么呢?抽象基类中的赋值?听起来可疑。
- @如果foo是一个带有数据成员的抽象类,那么我们就不能使用交换技巧。示例可以在这里找到:gamedev.net/topic/526089-c-data-members-in-an-abstract-class
- @卡米诺:你的要求毫无意义。赋值是针对值类,而不是多态的基类。您是否可能混淆了值和引用?
- @SBI,当你复制一个对象时,你需要复制对象的所有部分,对吗?假设bar是从foo派生的,foo是抽象类(具有纯虚拟函数),那么函数"foo&operator=(foo rhs)"将报告编译器错误
- @卡米诺:如果Foo是一个抽象的基类,那么您将通过Foo指针和引用来引用派生类,因为这就是多态类层次结构的用途。并且不能通过引用分配值。(通过两个车辆引用将汽车分配给飞机是没有意义的。)分配是针对值类的。如果继承与此有关,那么(希望)没有涉及到虚拟函数,因此也没有抽象的基类。(在多态类层次结构中,您需要clone(),而不是复制。)
在构造函数中调用operator=()既有潜在的缺点,也有潜在的收益。
缺点:
利润:
- 代码库变得不那么复杂,更容易维护。再次,明智地评估这一收益。如果您有一个包含两个字符串成员的结构,它可能不值得。另一方面,如果有一个类有50个数据成员(可能不应该,但这是另一篇文章的故事),或者数据成员彼此之间有复杂的关系,那么只使用一个init函数而不是两个或多个init函数可能会有很多好处。
您正在寻找Scott Meyers的有效C++项目12:复制对象的所有部分。