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

情况二:移动构造的生成条件

  1. 该类未声明任何复制操作
  2. 该类未声明任何移动操作
  3. 各类未声明任何析构函数

不满足以上条件时,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);
      |                        
posted @ 2023-03-03 16:56  小小灰迪  阅读(137)  评论(0编辑  收藏  举报