构造一个类去管理另外一个类时,需要遵循一个原则( The Rule of Three ),拷贝构造函数,赋值函数,析构函数,如果显示的实现其中一个,其他的都需要显示实现。如C++99中的auto_ptr用来管理普通指针类。
copy-swap是解决方案,可以很好地协助赋值运算符实现两件事:避免代码重复,并提供强大的异常保证。
从概念上讲,它通过使用拷贝构造函数的功能来创建数据的本地副本,然后使用交换功能获取复制的数据,将旧数据与新数据交换来工作。然后,临时副本将销毁,并随身携带旧数据。我们剩下的是新数据的副本。
为了使用copy-swap,我们需要三件事:
例子:
#include // std::copy
#include // std::size_t
class dumb_array
{
public:
// (default) constructor
dumb_array(std::size_t size = 0) :mSize(size),mArray(mSize ? new int[mSize]() : 0)
{}
// copy-constructor
dumb_array(const dumb_array& other) :mSize(other.mSize),mArray(mSize?new int[mSize]:0)
{
// note that this is non-throwing, because of the data
// types being used; more attention to detail with regards
// to exceptions must be given in a more general case, however
std::copy(other.mArray, other.mArray + mSize, mArray);
}
// destructor
~dumb_array()
{
delete[] mArray;
}
private:
std::size_t mSize;
int* mArray;
};
动态数组管理,dumb_array类对int*进行管理,已经定义了拷贝构造函数和析构函数,下面实现赋值函数。
不具备异常安全,只具备自我赋值安全性
// the hard part
dumb_array& operator=(const dumb_array& other)
{
if (this != &other) // (1) 避免自我赋值 造成重复分配内存和释放内存
{
// get rid of the old data...
delete[] mArray; // (2)
mArray = 0; // (2) *(see footnote for rationale)
// ...and put in the new
mSize = other.mSize; // (3)
mArray = mSize ? new int[mSize] : 0; // (3) new分配失败的情况mArray指向的就是一块已经释放的内存
std::copy(other.mArray, other.mArray + mSize, mArray); // (3)
}
return *this;
}
如果new出现异常,指针的值没变
这样就会导致代码膨胀,于是导致了另一个问题:代码冗余
dumb_array& operator=(const dumb_array& other)
{
if (this != &pOther) // (1)
{
// get the new data ready before we replace the old
std::size_t newSize = other.mSize;
int* newArray = newSize ? new int[newSize]() : 0; // (3)
std::copy(other.mArray, other.mArray + newSize, newArray); // (3)
// replace the old data (all are non-throwing)
delete [] mArray;
mSize = newSize;
mArray = newArray;
}
return *this;
}
copy and swap
#include // std::copy
#include // std::size_t
#include
using namespace std;
class dumb_array
{
public:
// (default) constructor
dumb_array(std::size_t size = 0) :mSize(size), mArray(mSize ? new int[mSize]() : 0)
{}
// copy-constructor
dumb_array(const dumb_array& other) :mSize(other.mSize), mArray(mSize ? new int[mSize] : 0)
{
// note that this is non-throwing, because of the data
// types being used; more attention to detail with regards
// to exceptions must be given in a more general case, however
std::copy(other.mArray, other.mArray + mSize, mArray);
}
// destructor
~dumb_array()
{
delete[] mArray;
}
// ...
//自定义一个swap友元类
friend void swap(dumb_array& first, dumb_array& second); // nothrow
//注意这里赋值是按照值赋值的,实参传递给形参的时候调用拷贝构造函数,初始化形参
//形参值在内部被修改了,但是不影响实参的使用
dumb_array& operator=(dumb_array other) // (1)
{
swap(*this, other); // (2)
return *this;
}
// ...
void print()
{
cout << (long)mArray << endl;
}
private:
std::size_t mSize;
int* mArray;
};
//自定义一个swap友元类
void swap(dumb_array& first, dumb_array& second) // nothrow
{
// enable ADL (not necessary in our case, but good practice)
using std::swap;
// by swapping the members of two classes,
// the two classes are effectively swapped
swap(first.mSize, second.mSize);
swap(first.mArray, second.mArray);
}
int main()
{
dumb_array array1(5);
array1.print();
dumb_array array2(7);
array2.print();
array1 = array2;
array1.print(); //交换完了 地址变化了,说明新分配了地址
array2.print(); //交换玩 地址没有改变
return 0;
}
#include // std::copy
#include // std::size_t
#include
using namespace std;
class dumb_array
{
public:
// (default) constructor
dumb_array(std::size_t size = 0) :mSize(size), mArray(mSize ? new int[mSize]() : 0)
{}
// copy-constructor
dumb_array(const dumb_array& other) :mSize(other.mSize), mArray(mSize ? new int[mSize] : 0)
{
// note that this is non-throwing, because of the data
// types being used; more attention to detail with regards
// to exceptions must be given in a more general case, however
std::copy(other.mArray, other.mArray + mSize, mArray);
}
// destructor
~dumb_array()
{
delete[] mArray;
}
// ...
//自定义一个swap友元类
friend void swap(dumb_array& first, dumb_array& second); // nothrow
//注意这里赋值是按照值赋值的,实参传递给形参的时候调用拷贝构造函数,初始化形参
//形参值在内部被修改了
//dumb_array& operator=(dumb_array other) // (1)
//{
// swap(*this, other); // (2)
// return *this;
//}
// ...
void print()
{
cout << (long)mArray << endl;
}
// move ctor 移动构造函数
dumb_array(dumb_array&& other)
{
std::cout << "move ctor" << std::endl;
mSize = other.mSize;
mArray = other.mArray;
if (other.mArray)
{
other.mArray = nullptr;
}
}
// move assignment移动赋值函数
dumb_array &operator=(dumb_array &&rhs)
{
std::cout << "move assignment" << std::endl;
//dumb_array tmp(rhs);
swap(*this, rhs);
return *this;
}
private:
std::size_t mSize;
int* mArray;
};
//自定义一个swap友元类
void swap(dumb_array& first, dumb_array& second) // nothrow
{
// enable ADL (not necessary in our case, but good practice)
using std::swap;
// by swapping the members of two classes,
// the two classes are effectively swapped
swap(first.mSize, second.mSize);
swap(first.mArray, second.mArray);
}
dumb_array getRightValue()
{
dumb_array array3(7);
return array3;//这里调用移动构造函数 调用完array3的值会发生变化
}
int main()
{
dumb_array array1(5);
array1.print();
dumb_array array2(7);
array2.print();
//array1 = getRightValue(); //
array1 = std::move(array2); //这里调用的是移动赋值函数 调用完array2值不变
array1.print(); //交换完了 地址变化了,说明新分配了地址
array2.print(); //交换玩 地址没有改变
return 0;
}
dumb_array& operator=(dumb_array other) 与**dumb_array &operator=(dumb_array &&rhs)**不能同时定义否则会编译出错。