1 概述
C++中的大三法则是类的拷贝构造函数,赋值运算符和析构函数这三个函数只要一个出现,其它两个也要出现。
从C++11开始引入右值引用&&,多了移动构造函数和移动赋值函数,大三法则就变为大五法则。
2 大三法则
C++中的大三法则是类的拷贝构造函数,赋值运算符和析构函数这三个函数只要一个出现,其它两个也要出现。
例子:
class Array
{int32_t *array_;uint32_t size_;friend std::ostream & operator << (std::ostream &os, Array const& obj);
public:Array(uint32_t n = 0): array_(new int32_t[n]), size_(n){std::cout << "Array(int)" << std::endl;}Array(Array const& r)//拷贝构造函数: size_(r.size_), array_(new int32_t[size_]){if(array_)memcpy(array_, r.array_, size_ * sizeof(int32_t));std::cout << "Array(Array const&)" << std::endl;}Array& operator=(Array const& r)//赋值运算符{if(this == &r)return *this;if(array_)delete []array_;size_ = r.size_;array_ = new int32_t[size_];if(array_)memcpy(array_, r.array_, size_ * sizeof(int32_t));std::cout << "operator=(Array const&)" << std::endl;return *this;}~Array()//析构函数{delete []array_;std::cout << " ~Array()" << std::endl;}uint32_t size() const { return size_; }bool setValue(uint32_t index, int32_t value){if(index >= size_)return false;array_[index] = value;return true;}bool getValue(uint32_t index, int32_t& value) const{if(index >= size_)return false;value = array_[index];return true;}
};std::ostream & operator << (std::ostream &os, Array const& obj)
{for(uint32_t i = 0; i < obj.size_; i++)os << obj.array_[i] << " ";if(obj.size_ == 0)os << "empty";os << std::endl;return os;
}int main(int argc, char *argv[])
{Array array1(5);for(uint32_t i = 0; i < array1.size(); i++)array1.setValue(i, i + 1);Array array2 = array1;Array array3;array2.setValue(3, 10);array3 = array2;array3.setValue(5, 10);array3.setValue(4, 8);std::cout << "array1: " << array1<< "array2: " << array2<< "array3: " << array3;return 0;
}
运行结果:
Array(int)
Array(Array const&)
Array(int)
operator=(Array const&)
array1: 1 2 3 4 5
array2: 1 2 3 10 5
array3: 1 2 3 10 5~Array()~Array()~Array()
3 大五法则
C++中的大五法则是类的拷贝构造函数,移动构造函数,赋值运算符,移动赋值函数和析构函数这五个函数只要一个出现,其它四个也要出现。
给Array增加移动构造函数和移动赋值函数:
class Array
{int32_t *array_;uint32_t size_;friend std::ostream & operator << (std::ostream &os, Array const& obj);
public:Array(Array && r): array_(r.array_), size_(r.size_){r.array_ = nullptr;r.size_ = 0;}Array& operator=(Array && r){if(this == &r)return *this;if(array_)delete []array_;array_ = r.array_;size_ = r.size_;r.array_ = nullptr;r.size_ = 0;return *this;}
};
int main(int argc, char *argv[])
{Array array1(5);for(uint32_t i = 0; i < array1.size(); i++)array1.setValue(i, i + 1);Array array2 = array1; //拷贝构造函数Array array3;array2.setValue(3, 10);array3 = array2;//赋值运算符array3.setValue(5, 10);std::cout << "array1: " << array1<< "array2: " << array2<< "array3: " << array3;Array array4 = std::move(array3);//移动构造函数Array array5;array5 = std::move(array2);//移动赋值函数std::cout << "array4: " << array4<< "array5: " << array5<< "array3: " << array3<< "array2: " << array2;return 0;
}
运行结果:
Array(int)
Array(Array const&)
Array(int)
operator=(Array const&)
array1: 1 2 3 4 5
array2: 1 2 3 10 5
array3: 1 2 3 10 5
Array(Array &&)
Array(int)
operator=(Array &&)
array4: 1 2 3 10 5
array5: 1 2 3 10 5
array3: empty
array2: empty~Array()~Array()~Array()~Array()~Array()
4 前向兼容
前面我我们为Array类型增加了移动构造函数和移动赋值函数,这是C++11版本才有的特性,在C++11之前版本没有该特性,代码肯定是编译不过的。如何修改代码可以前向兼容老版本呢?答案是利用宏__cplusplus。__cplusplus是C++中定义的宏,用来表示C++的版本。
#include <iostream>int main(int argc, char *argv[])
{std::cout << "c++ version: " << __cplusplus << std::endl;return 0;
}
4.1 C++98
g++ -std=c++98 test.cpp -o test
./test
c++ version: 199711
4.2 C++11
g++ -std=c++11 test.cpp -o test
./test
c++ version: 201103
4.3 C++14
g++ -std=c++14 test.cpp -o test
./test
c++ version: 201402
4.4 C++17
g++ -std=c++17 test.cpp -o test
./test
c++ version: 201703
4.5 前向兼容代码
从上面看出__cplusplus大于等201103L是C++11及之后版本,代码修改如下:
class Array
{int32_t *array_;uint32_t size_;friend std::ostream & operator << (std::ostream &os, Array const& obj);
public:
#if __cplusplus >= 201103L //前向兼容Array(Array && r): array_(r.array_), size_(r.size_){r.array_ = nullptr;r.size_ = 0;std::cout << "Array(Array &&)" << std::endl;}Array& operator=(Array && r){if(this == &r)return *this;if(array_)delete []array_;array_ = r.array_;size_ = r.size_;r.array_ = nullptr;r.size_ = 0;std::cout << "operator=(Array &&)" << std::endl;return *this;}
#endif
};
int main(int argc, char *argv[])
{Array array1(5);for(uint32_t i = 0; i < array1.size(); i++)array1.setValue(i, i + 1);Array array2 = array1; //拷贝构造函数Array array3;array2.setValue(3, 10);array3 = array2;//赋值运算符array3.setValue(5, 10);std::cout << "array1: " << array1<< "array2: " << array2<< "array3: " << array3;#if __cplusplus >= 201103L //前向兼容Array array4 = std::move(array3);Array array5;array5 = std::move(array2);std::cout << "array4: " << array4<< "array5: " << array5<< "array3: " << array3<< "array2: " << array2;
#endifstd::cout << "c++ version: " << __cplusplus <<std::endl;return 0;
}