为了正确处理对象复制,经验法则是三规则.使用C++ 11,移动语义是一个东西,所以它是五条规则.然而,在这里和互联网上的讨论中,我也看到了对四条规则(一半)的引用,它是五条规则和复制交换习语的组合.
究竟是什么(四分之一)呢?需要实现哪些功能,每个功能的主体应该是什么样的?一半的功能是什么?与五法则相比,这种方法有任何缺点或警告吗?
这是一个类似于我当前代码的参考实现.如果这不正确,那么正确的实现会是什么样的?
//I understand that in this example, I could just use `std::unique_ptr`.
//Just assume it's a more complex resource.
#include <utility>
class Foo {
public:
//We must have a default constructor so we can swap during copy construction.
//It need not be useful, but it should be swappable and deconstructable.
//It can be private, if it's not truly a valid state for the object.
Foo() : resource(nullptr) {}
//Normal …Run Code Online (Sandbox Code Playgroud) c++ copy-constructor assignment-operator copy-and-swap c++11
class_name & class_name :: operator= ( const class_name & ) (2)
Run Code Online (Sandbox Code Playgroud)
(2)当不能使用复制和交换习语时,复制赋值运算符的典型声明
我们何时应该避免使用复制和交换习惯用法?
什么时候"完全不能使用"?
是否有现实生活中的情况,即复制和交换以及零规则都不适用?
我确实找到了这个问题,但它过于具体,没有包含任何关于如何识别此类案例的指南.
我正在尝试将复制和交换习惯用法放入可重用的混音中:
template<typename Derived>
struct copy_and_swap
{
Derived& operator=(Derived copy)
{
Derived* derived = static_cast<Derived*>(this);
derived->swap(copy);
return *derived;
}
};
Run Code Online (Sandbox Code Playgroud)
我打算通过CRTP混合:
struct Foo : copy_and_swap<Foo>
{
Foo()
{
std::cout << "default\n";
}
Foo(const Foo& other)
{
std::cout << "copy\n";
}
void swap(Foo& other)
{
std::cout << "swap\n";
}
};
Run Code Online (Sandbox Code Playgroud)
但是,一个简单的测试显示它不起作用:
Foo x;
Foo y;
x = y;
Run Code Online (Sandbox Code Playgroud)
这仅打印两次"默认",不打印"复制"或"交换".我在这里错过了什么?
我正在测试一些代码,其中std::vector一个类中有一个数据成员.类是既可以复印和活动,并operator=描述实现这里使用复制和交换成语.
如果有两个vectors,比如v1大容量和v2小容量,并被v2复制到v1(v1 = v2),则v1在分配后保留大容量 ; 这是有道理的,因为下一次v1.push_back()调用不必强制新的重新分配(换句话说:释放已经可用的内存,然后重新分配它来增长向量没有多大意义).
但是,如果对具有as数据成员的类进行相同的赋值vector,则行为不同,并且在赋值之后不保留更大的容量.
如果不使用复制operator=和交换习惯用法,并且复制和移动operator=是分开实现的,那么行为就像预期的那样(对于普通的非成员vectors).
这是为什么?我们是否应该遵循复制和交换习惯用法,而是分别实施operator=(const X& other)(复制 op=)和operator=(X&& other)(移动 op=)以获得最佳性能?
这是一个可重复的测试输出与复制和交换成语(注意如何在这种情况下,之后 x1 = x2,x1.GetV().capacity()就是1000,不1,000,000):
Run Code Online (Sandbox Code Playgroud)C:\TEMP\CppTests>cl /EHsc …
我正在学习c ++,最近我学习了(这里是堆栈溢出)有关复制和交换的习惯用法,我对它有一些问题.所以,假设我有以下类使用复制和交换习惯用法,例如:
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];}
};
Run Code Online (Sandbox Code Playgroud)
我的问题是,假设我有另一个类,它有一个Foo对象作为数据但没有指针或其他可能需要自定义复制或赋值的资源:
class Bar {
private:
Foo bar;
public:
Bar(Foo foo) : bar(foo) {};
~Bar(){};
Bar(Bar …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用纯虚方法和'复制和交换'惯用法实现虚拟类,但我遇到了一些问题.代码将无法编译,因为我在包含纯虚方法的类A的assign运算符中创建实例.
有没有办法如何使用纯虚方法和复制和交换成语?
class A
{
public:
A( string name) :
m_name(name) { m_type = ""; }
A( const A & rec) :
m_name(rec.m_name), m_type(rec.m_type) {}
friend void swap(A & lhs, A & rhs)
{
std::swap(lhs.m_name, rhs.m_name);
std::swap(lhs.m_type, rhs.m_type);
}
A & operator=( const A & rhs)
{
A tmp(rhs);
swap(*this, tmp);
return *this;
}
friend ostream & operator<<( ostream & os,A & x)
{
x.print(os);
return os;
}
protected:
virtual void print(ostream & os) =0;
string m_type;
string m_name;
}; …Run Code Online (Sandbox Code Playgroud) 借用Howard Hinnant的例子并将其修改为使用copy-and-swap,这是op =线程安全吗?
struct A {
A() = default;
A(A const &x); // Assume implements correct locking and copying.
A& operator=(A x) {
std::lock_guard<std::mutex> lock_data (_mut);
using std::swap;
swap(_data, x._data);
return *this;
}
private:
mutable std::mutex _mut;
std::vector<double> _data;
};
Run Code Online (Sandbox Code Playgroud)
我相信这个线程安全(记住op =的参数是通过值传递的),我能找到的唯一问题是在地毯下扫描的那个:复制ctor.但是,它是一种罕见的类,它允许复制赋值而不是复制构造,因此在两种选择中都存在同样的问题.
鉴于自我分配是如此罕见(至少在这个例子中)我不介意额外的副本如果发生,考虑这个!=&rhs的潜在优化要么可以忽略不计,要么是悲观化.与原始策略(下面)相比,是否还有其他理由更喜欢或避免它?
A& operator=(A const &rhs) {
if (this != &rhs) {
std::unique_lock<std::mutex> lhs_lock( _mut, std::defer_lock);
std::unique_lock<std::mutex> rhs_lock(rhs._mut, std::defer_lock);
std::lock(lhs_lock, rhs_lock);
_data = rhs._data;
}
return *this;
}
Run Code Online (Sandbox Code Playgroud)
顺便说一句,我认为这简洁地处理了复制文件,至少在本课程中,即使它有点迟钝:
A(A const &x) : _data {(std::lock_guard<std::mutex>(x._mut), x._data)} {}
Run Code Online (Sandbox Code Playgroud) 我收到以下错误:
[matt ~] g++ -std=c++11 main.cpp -DCOPY_AND_SWAP && ./a.out
main.cpp: In function ‘int main(int, const char* const*)’:
main.cpp:101:24: error: ambiguous overload for ‘operator=’ in ‘move = std::move<Test&>((* & copy))’
main.cpp:101:24: note: candidates are:
main.cpp:39:7: note: Test& Test::operator=(Test)
main.cpp:52:7: note: Test& Test::operator=(Test&&)
Run Code Online (Sandbox Code Playgroud)
编译以下代码时:
#include <iostream>
#include <unordered_map>
class Test final {
public:
typedef std::unordered_map<std::string, std::string> Map;
public:
Test();
explicit Test(Map&& map);
~Test();
Test(const Test& other);
Test(Test&& test);
#ifdef COPY_AND_SWAP
Test& operator=(Test other);
#else
Test& operator=(const Test& other);
#endif
Test& operator=(Test&& other); …Run Code Online (Sandbox Code Playgroud) c++ operator-overloading overload-resolution copy-and-swap c++11
我最近在StackOverflow上读到了关于什么是复制和交换习语的答案?并且知道复制和交换习语可以
避免代码重复,并提供强大的异常保证.
但是,当我查看SGI STL deque 实现时,我发现它没有使用这个成语.我想知道为什么不,如果成语在某种程度上像一个"最佳实践"?
deque& operator= (const deque& __x) {
const size_type __len = size();
if (&__x != this) {
if (__len >= __x.size())
erase(copy(__x.begin(), __x.end(), _M_start), _M_finish);
else {
const_iterator __mid = __x.begin() + difference_type(__len);
copy(__x.begin(), __mid, _M_start);
insert(_M_finish, __mid, __x.end());
}
}
return *this;
}
Run Code Online (Sandbox Code Playgroud) 如果我有一个类如
class Foo{
public:
Foo(){...}
Foo(Foo && rhs){...}
operator=(Foo rhs){ swap(*this, rhs);}
void swap(Foo &rhs);
private:
Foo(const Foo&);
// snip: swap code
};
void swap(Foo& lhs, Foo& rhs);
Run Code Online (Sandbox Code Playgroud)
如果我没有复制构造函数,是否有意义实现operator = by value和swap?它应该防止复制我的类对象Foo但允许移动.
这个类是不可复制的,所以我不能复制构造或复制分配它.
我用这个测试了我的代码,它似乎有我想要的行为.
#include <utility>
#include <cstdlib>
using std::swap;
using std::move;
class Foo{
public: Foo():a(rand()),b(rand()) {}
Foo(Foo && rhs):a(rhs.a), b(rhs.b){rhs.a=rhs.b=-1;}
Foo& operator=(Foo rhs){swap(*this,rhs);return *this;}
friend void swap(Foo& lhs, Foo& rhs){swap(lhs.a,rhs.a);swap(lhs.b,rhs.b);}
private:
//My compiler doesn't yet implement deleted constructor
Foo(const Foo&);
private:
int a, b;
};
Foo …Run Code Online (Sandbox Code Playgroud) c++ rvalue-reference assignment-operator copy-and-swap c++11