1、基本原则
C++98的三法则:
如果需要析构函数,则一定需要拷贝构造函数和拷贝赋值操作符。一般是因为存在指针, 通过自定义的拷贝构造函数和赋值运算符防治浅拷贝问题,获取管理了系统的资源,需要及时释放掉。
复制(拷贝)构造函数
拷贝赋值操作符
析构函数
class X {
public:
X (const X& lvalue); //copy constructor
X& operator=(const X& lvalue); //copy assignment operator
~X();
private:
T* p; //means the class is a nontrivial
};
C++11的五法则:
与三之法则不同的是,不提供移动构造函数和移动赋值运算符通常不是错误,但会导致失去优化机会。
复制(拷贝)构造函数
移动构造函数
拷贝赋值操作符
移动赋值操作符
析构函数
class X {
public:
X (const X& lvalue); //copy constructor
X (X&& rvalue); //move constructor
X& operator=(const X& lvalue); //copy assignment operator
X& operator=(X&& rvalue); //move assignment operator
~X();
private:
T* p; //means the class is a nontrivial
};
2 实例类设计
这是个普通的模板类,实现了五法则,即复制构造函数,赋值操作符,析构函数,移动构造函数,移动操作符。
#pragma once #include#include #include template class Array2D { public: Array2D(unsigned int nj, unsigned int ni, std::string name); Array2D(const Array2D & other); Array2D & operator=(const Array2D & other); virtual ~Array2D(); // Implement Move Semantics // Note: It is usually best to mark move operators as noexcept // This allows certain optimizations in the standard library // when the class is used in a container. Array2D(Array2D && that) noexcept :_ni(that._ni) , _nj(that._nj) ,_name(that._name) ,_datPtr(nullptr) // Set the state so we know it is undefined { swap(*this, that); } Array2D & operator=(Array2D && that) noexcept { swap(*this, that); return *this; } unsigned int getNi() { return _ni; } //column unsigned getNj() { return _nj; } //rows unsigned int getNi()const { return _ni; } //column unsigned getNj()const { return _nj; } //rows vType& getValue(unsigned int j, unsigned int i); const vType& getValue(unsigned int j, unsigned int i)const; void printSelf(); void printSelf()const; void printSelf(std::ofstream&fout); void printSelf(std::ofstream&fout)const; void printSelf(const std::string & fileName); void printSelf(const std::string& fileName)const; private: void swap(Array2D & lhs, Array2D & rhs) noexcept; protected: unsigned int _ni; unsigned int _nj; std::string _name; vType* _datPtr{ nullptr }; }; template inline Array2D ::Array2D(unsigned int nj, unsigned int ni, std::string name) :_ni(ni), _nj(nj), _name(name), _datPtr(nullptr) { _datPtr = new vType[_ni * _nj]; } template inline Array2D ::Array2D(const Array2D & other): _ni(other._ni), _nj(other._nj), _name(other._name), _datPtr(nullptr) { _datPtr = new vType[_ni * _nj]; for (int i = 0; i < _ni * _nj; i++) { _datPtr[i] = other._datPtr[i]; } } template inline Array2D & Array2D ::operator=(const Array2D & other) { // Use copy and swap idiom to implement assignment. Array2D copy(other); swap(*this, copy); return *this; } template inline Array2D ::~Array2D() { if (_datPtr != nullptr) { delete _datPtr; _datPtr = nullptr; } } template inline vType& Array2D ::getValue(unsigned int j, unsigned int i) { return _datPtr[j * _ni + i]; } template inline const vType& Array2D ::getValue(unsigned int j, unsigned int i) const { return _datPtr[j * _ni + i]; } template inline void Array2D ::printSelf() { for (int j = _nj - 1; j >= 0; j--) { for (int i = 0; i < _ni; i++) { std::cout << _datPtr[j * _ni + i] << "t"; } std::cout << std::endl; } } template inline void Array2D ::printSelf() const { for (int j = _nj - 1; j >= 0; j--) { for (int i = 0; i < _ni; i++) { std::cout << _datPtr[j * _ni + i] << "t"; } std::cout << std::endl; } } template inline void Array2D ::printSelf(std::ofstream& fout) { for (int j = _nj - 1; j >= 0; j--) { for (int i = 0; i < _ni; i++) { fout << _datPtr[j * _ni + i] << "t"; } fout << std::endl; } } template inline void Array2D ::printSelf(std::ofstream& fout) const { for (int j = _nj - 1; j >= 0; j--) { for (int i = 0; i < _ni; i++) { fout << _datPtr[j * _ni + i] << "t"; } fout << std::endl; } } template inline void Array2D ::printSelf(const std::string& fileName) { std::ofstream fout(fileName); if (!fout.is_open()) { std::cout << "fail to open " << fileName << std::endl; return; } printSelf(fout); fout.close(); } template inline void Array2D ::printSelf(const std::string& fileName) const { std::ofstream fout(fileName); if (!fout.is_open()) { std::cout << "fail to open " << fileName << std::endl; return; } printSelf(fout); fout.close(); } template inline void Array2D ::swap(Array2D & lhs, Array2D & rhs) noexcept { swap(lhs._ni, rhs._ni); swap(lhs._nj, rhs._nj); swap(lhs._name, rhs._name); swap(lhs._datPtr, rhs._datPtr); }
3 类的调用测试
#include "Array2D.h" #includeint main(int argc, char* argv[]) { unsigned int ni = 4; unsigned int nj = 3; Array2D arrayTest{ nj, ni, "test" }; auto arrayTest2 = arrayTest; std::random_device dv; std::default_random_engine rd(dv()); std::uniform_real_distribution real_dist; for (unsigned int j = 0; j < nj; j++) { for (unsigned int i = 0; i < ni; i++) { arrayTest.getValue(j, i) = real_dist(rd); } } std::cout << "test1" << std::endl; arrayTest.printSelf(); arrayTest.printSelf("test.txt"); std::cout << "test2" << std::endl; arrayTest2.printSelf(); arrayTest2.printSelf("test2.txt"); std::cout << "test3" << std::endl; auto arrayTest3 = Array2D (arrayTest); arrayTest3.printSelf(); arrayTest3.printSelf("test3.txt"); std::cout << "test4" << std::endl; auto arrayTest4 = arrayTest; arrayTest4.printSelf(); arrayTest4.printSelf("test4.txt"); return EXIT_SUCCESS; }
结果
test1 0.133351 0.995246 0.739061 0.33874 0.523315 0.40387 0.928565 0.817014 0.458272 0.0335825 0.300851 0.202705 test2 -6.27744e+66 -6.27744e+66 -6.27744e+66 -6.27744e+66 -6.27744e+66 -6.27744e+66 -6.27744e+66 -6.27744e+66 -6.27744e+66 -6.27744e+66 -6.27744e+66 -6.27744e+66 test3 0.133351 0.995246 0.739061 0.33874 0.523315 0.40387 0.928565 0.817014 0.458272 0.0335825 0.300851 0.202705 test4 0.133351 0.995246 0.739061 0.33874 0.523315 0.40387 0.928565 0.817014 0.458272 0.0335825 0.300851 0.202705



