C++三法则和五法则的实例测试
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 <string>
#include <iostream>
#include <fstream>
template<typename vType>
class Array2D
{
public:
Array2D(unsigned int nj, unsigned int ni, std::string name);
Array2D(const Array2D<vType>& other);
Array2D<vType>& operator=(const Array2D<vType>& 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<vType>&& 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<vType>& operator=(Array2D<vType>&& 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<vType>& lhs, Array2D<vType>& rhs) noexcept;
protected:
unsigned int _ni;
unsigned int _nj;
std::string _name;
vType* _datPtr{ nullptr };
};
template<typename vType>
inline Array2D<vType>::Array2D(unsigned int nj, unsigned int ni, std::string name)
:_ni(ni), _nj(nj), _name(name), _datPtr(nullptr) {
_datPtr = new vType[_ni * _nj];
}
template<typename vType>
inline Array2D<vType>::Array2D(const Array2D<vType>& 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<typename vType>
inline Array2D<vType>& Array2D<vType>::operator=(const Array2D<vType>& other)
{
// Use copy and swap idiom to implement assignment.
Array2D<vType> copy(other);
swap(*this, copy);
return *this;
}
template<typename vType>
inline Array2D<vType>::~Array2D()
{
if (_datPtr != nullptr) {
delete _datPtr;
_datPtr = nullptr;
}
}
template<typename vType>
inline vType& Array2D<vType>::getValue(unsigned int j, unsigned int i)
{
return _datPtr[j * _ni + i];
}
template<typename vType>
inline const vType& Array2D<vType>::getValue(unsigned int j, unsigned int i) const
{
return _datPtr[j * _ni + i];
}
template<typename vType>
inline void Array2D<vType>::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<typename vType>
inline void Array2D<vType>::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<typename vType>
inline void Array2D<vType>::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<typename vType>
inline void Array2D<vType>::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<typename vType>
inline void Array2D<vType>::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<typename vType>
inline void Array2D<vType>::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<typename vType>
inline void Array2D<vType>::swap(Array2D<vType>& lhs, Array2D<vType>& 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"
#include <random>
int main(int argc, char* argv[]) {
unsigned int ni = 4;
unsigned int nj = 3;
Array2D<double> arrayTest{ nj, ni, "test" };
auto arrayTest2 = arrayTest;
std::random_device dv;
std::default_random_engine rd(dv());
std::uniform_real_distribution<double> 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<double>(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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具