C++类的默认函数(特种函数)
目录
六种默认函数
class Base
{
public:
Base() = default; // 无参构造函数
Base(const Base& obj) = default; // 拷贝构造
Base(Base&& obj) = default; // 移动构造
Base& operator= (const Base& obj) = default; // 复制赋值操作符重载函数
Base& operator= (Base&& obj) = default; // 移动赋值操作符重载函数
~Base() = default; // 析构函数
};
情况一:默认不显示地声明——自行生成各种默认函数
示例1.1:不显示声明,调用时自动生成
#include <iostream>
#include <chrono>
#include <unordered_map>
using namespace std;
using namespace std::chrono;
class Widget{
public:
// Widget()=default;
// ~Widget()=default;
// // 拷贝构造
// Widget(const Widget&) = default;
// // 复制赋值运算符
// Widget& operator=(const Widget& obj) = default;
// // 移动构造
// Widget(Widget&&) = default;
// // 移动赋值预算符
// Widget& operator=(Widget&&) = default;
void setValues(){
std::string temp = "test 111111111111111111111111111111111111111111111111111111111111111";
for(size_t i=0; i< 1000; i++){
values[i] = temp;
}
}
std::unordered_map<int ,std::string> values;
};
// g++ test.cpp -std=c++11 -o test
int main(){
auto start_time = steady_clock::now();
// auto widget = Widget();
Widget widget;
widget.setValues();
auto end_time = steady_clock::now();
auto ts = duration_cast<microseconds>(end_time-start_time);
std::cout<<"默认构造时间:"<< ts.count() << " ms" << std::endl;
// 赋值构造
start_time = steady_clock::now();
// auto widget_copy = Widget(widget); // 与下一句等价。调用的是拷贝构造
// auto widget_copy = widget; // 与下一句等价。调用的是拷贝构造
auto widget_copy(widget);
end_time = steady_clock::now();
ts = duration_cast<microseconds>(end_time-start_time);
std::cout<<"赋值构造时间:"<< ts.count() << " ms" << std::endl;
// std::cout<<"copy value size: "<< widget_copy.values.size() << std::endl;
// 复制赋值运算符
start_time = steady_clock::now();
Widget widget_copy_;
widget_copy_ = widget; // 复制赋值运算符
end_time = steady_clock::now();
ts = duration_cast<microseconds>(end_time-start_time);
std::cout<<"复制赋值运算符时间:"<< ts.count() << " ms" << std::endl;
std::cout<<" 复制赋值运算符 value size: "<< widget_copy_.values.size() << std::endl;
// 移动构造
start_time = steady_clock::now();
auto widget_move = std::move(widget_copy_); // 与下一句等价。调用的是拷贝构造
// auto widget_move = Widget(std::move(widget_copy_)); // 与下一句等价。调用的是拷贝构造
// auto widget_move(std::move(widget_copy_));
end_time = steady_clock::now();
ts = duration_cast<microseconds>(end_time-start_time);
std::cout<<"移动构造时间:"<< ts.count() << " ms" << std::endl;
std::cout<<" 移动构造 value size: "<< widget_move.values.size() << std::endl;
// 移动赋值运算符
start_time = steady_clock::now();
Widget widget_move_;
widget_move_ = std::move(widget_move); // 移动赋值运算符
end_time = steady_clock::now();
ts = duration_cast<microseconds>(end_time-start_time);
std::cout<<"移动赋值运算符时间:"<< ts.count() << " ms" << std::endl;
std::cout<<" 移动赋值运算符 value size: "<< widget_move_.values.size() << std::endl;
}
输出
默认构造时间:625 ms
赋值构造时间:387 ms
复制赋值运算符时间:404 ms
复制赋值运算符 value size: 1000
移动构造时间:0 ms
移动构造 value size: 1000
移动赋值运算符时间:0 ms
移动赋值运算符 value size: 1000
情况二:移动构造的生成条件
- 该类未声明任何复制操作
- 该类未声明任何移动操作
- 各类未声明任何析构函数
不满足以上条件时,c++不会默认生成移动构造或移动赋值操作符,退化为拷贝构造或拷贝赋值运算符
示例2.1: 增加析构、拷贝构造、拷贝赋值运算符,移动操作退化
#include <iostream>
using namespace std;
class Widget{
public:
Widget()=default;
~Widget(){
std::cout << " 析构函数" <<std::endl;
};
// // 拷贝构造
Widget(const Widget&){
std::cout << " 拷贝构造函数" <<std::endl;
}
// // 复制赋值运算符
Widget& operator=(const Widget& obj){
std::cout << " 拷贝赋值运算符" <<std::endl;
}
// // 移动构造
// Widget(Widget&&){
// std::cout << " 移动构造函数" <<std::endl;
// }
// // 移动赋值预算符
// Widget& operator=(Widget&&) = default;
};
// g++ test.cpp -std=c++11 -o test
int main(){
Widget widget;
// 赋值构造
auto widget_copy(widget);
// 复制赋值运算符
Widget widget_copy_;
widget_copy_ = widget;
// 移动构造
auto widget_move = std::move(widget_copy_);
// 移动赋值运算符
Widget widget_move_;
widget_move_ = std::move(widget_move);
}
示例2.2: 只增加析构函数,移动构造退化为复制构造
class Widget{
public:
Widget()=default;
~Widget(){
std::unordered_map<int ,std::string> empty;
values.clear();
std::swap(values, empty);
};
... // 只做了以上修改,增加了析构函数
};
输出:
默认构造时间:208 ms
赋值构造时间:137 ms
复制赋值运算符时间:148 ms
复制赋值运算符 value size: 1000
移动构造时间:112 ms
移动构造 value size: 1000
移动赋值运算符时间:117 ms
移动赋值运算符 value size: 1000
情况三:显示地声明移动函数,就默认删除拷贝操作
示例3.1:显示地声明移动函数,就默认删除拷贝操作
‘constexpr Widget::Widget(const Widget&)’ is implicitly declared as deleted because ‘Widget’ declares a move constructor or move assignment operator
#include <iostream>
using namespace std;
// @情况三:显示地声明移动函数,就默认删除拷贝操作
class Widget{
public:
Widget()=default;
// 移动构造
Widget(Widget&&){
std::cout << " 移动构造函数" <<std::endl;
}
};
// g++ test.cpp -std=c++11 -o test
int main(){
Widget widget;
// 赋值构造
auto widget_copy(widget); // error
// 复制赋值运算符
Widget widget_copy_;
widget_copy_ = widget; // error
// 移动构造
auto widget_move = std::move(widget_copy_);
// 移动赋值运算符
Widget widget_move_;
widget_move_ = std::move(widget_move); // // error :默认会调用拷贝操作符,但是已经被删除
}
输出
test2_2.cpp: In function ‘int main()’:
test2_2.cpp:35:28: error: use of deleted function ‘constexpr Widget::Widget(const Widget&)’
35 | auto widget_copy(widget);
| ^
test2_2.cpp:3:7: note: ‘constexpr Widget::Widget(const Widget&)’ is implicitly declared as deleted because ‘Widget’ declares a move constructor or move assignment operator
3 | class Widget{
| ^~~~~~
test2_2.cpp:40:20: error: use of deleted function ‘Widget& Widget::operator=(const Widget&)’
40 | widget_copy_ = widget; // 复制赋值运算符
| ^~~~~~
test2_2.cpp:3:7: note: ‘Widget& Widget::operator=(const Widget&)’ is implicitly declared as deleted because ‘Widget’ declares a move constructor or move assignment operator
3 | class Widget{
| ^~~~~~
test2_2.cpp:47:41: error: use of deleted function ‘Widget& Widget::operator=(const Widget&)’
47 | widget_move_ = std::move(widget_move);
|