我正在学习c++,最近我学习了有关 copy-and-swap 的习惯用法(在堆栈溢出中),我对此有一些疑问。因此,假设我有以下使用 copy-and-swap 惯用法的类,例如:
class Foo {
private:
int * foo;
int size;
public:
Foo(size_t size) : size(size) { foo = new int[size](); }
~Foo(){delete foo;}
Foo(Foo const& other){
size = other.size;
foo = new int[size];
copy(other.foo, other.foo + size, foo);
}
void swap(Foo& other) {
std::swap(foo, other.foo);
std::swap(size, other.size);
}
Foo& operator=(Foo g) {
g.swap(*this);
return *this;
}
int& operator[] (const int idx) {return foo[idx];}
};
我的问题是,假设我有另一个类,其中有一个Foo对象作为数据,但没有可能需要自定义复制或赋值的指针或其他资源:
class Bar {
private:
Foo bar;
public:
Bar(Foo foo) : bar(foo) {};
~Bar(){};
Bar(Bar const& other) : bar(other.bar) {};
Bar& operator=(Bar other) {bar = other.bar;}
};
现在我有一系列问题:
Bar
类实现的方法和构造函数是否安全?使用了Foo
的 copy-and-swap 功能后,确保在分配或复制Bar
时不会造成任何危害吗? operator=
的参数按值传递时,将为该参数调用复制构造函数以生成对象的临时拷贝,然后是此拷贝与*this
交换吗?如果我通过operator=
中的引用传递了我,那么会有一个大问题,对吗? Foo
时无法提供完全的安全性吗? 最佳答案
关于copy-ctor:始终是安全的(全有或全无)。它要么完成(全部),要么抛出异常(什么都没有)。
如果您的类(class)仅由一个成员组成(即也没有基类),则赋值运算符将与成员类(class)一样安全。如果您有一个以上的成员,则赋值运算符将不再是“全有或全无”。第二个成员的赋值运算符可能会引发异常,在这种情况下,将为对象分配“半路”。这意味着您需要在新类中再次实现 copy-and-swap 以获取“全有或全无”分配。
但是,从某种意义上讲,您不会泄漏任何资源,它仍然是“安全的”。当然,每个成员的状态将是一致的-只是新类的状态是不一致的,因为一个成员被分配而另一个成员没有被分配。
是的,通过引用传递是强制性的。复制构造函数是用于复制对象的构造函数,因此它不能按值接受其参数,因为这将意味着必须复制该参数。这将导致无限递归。 (将为参数调用copy-ctor,这意味着将为参数调用copy-ctor,这意味着...)。对于交换,原因是另一个原因:如果要按值传递参数,则永远不能使用交换来真正交换两个对象的内容-交换的“目标”将是最初传递的对象的拷贝,它将立即被销毁。
恩,那就对了。但是,通过引用引用常量作为参数,构造本地拷贝,然后与本地拷贝交换也是很常见的。但是,按引用按常量的方式有一些缺点(它禁用了一些优化)。如果您没有实现 copy-and-swap ,则可能应该通过引用常量来传递。
我不知道。当然,使用多线程总是可以使事情失败(如果未正确同步),但这应该是显而易见的。