【Effective C++】构造/析构/赋值运算

发布时间:2024年01月20日

Item05 了解C++默默编写并调用了哪些函数

1. 定义空类并使用空类定义变量的时候,编译器会默认生成以下函数:

  • (无参)默认构造函数
  • 拷贝构造函数
  • 拷贝赋值函数
  • 析构函数
// 只有需要的时候才会创建
class Empty {
public:
    Empty() {}                  // 默认构造函数
    Empty(const Empty& rhs) {}  // 默认拷贝构造
    ~Empty() {}                 // 默认析构函数

    Empty& operator=(const Empty& rhs) {} // 默认拷贝赋值函数
};

2. 如果显式定义了其中的任何一个特殊成员函数,编译器将不会生成默认的对应函数;

  • 如,在该例子中声明了构造函数,然后定义一个变量,会报 no matching function 的错误;
  • 对于默认的拷贝构造的操作,
    • nobj3初始化nameValue时,会调用string的拷贝构造,参数为nobj1.nameValue;
    • nobj3初始化objectValue时,会将nobj1.objectValue每个bits拷贝到nobj3.objectValue;
  • 对于默认拷贝赋值操作,行为和拷贝构造一样
template<typename T>
class NameObject {
public:
    NameObject(const std::string& name, const T& value) : nameValue(name), objectValue(value) { }
private:
    std::string nameValue;
    T objectValue;
};

#include "item_05.h"
int main() {
    NameObject<int> nobj;
    NameObject<int> nobj1("name", 5);
    NameObject<int> nobj2("nobj2", 10);
    NameObject<int> nobj3(nobj1); // copy construct
    nobj1 = nobj2;                // copy assignment
    return 0;
}

// main.cpp:9:21: error: no matching function for call to ‘NameObject<int>::NameObject()’
//     9 |     NameObject<int> nobj;

3. 默认拷贝赋值函数只有生成代码合法的情况下才会被创建

  • 如果成员变量是引用或者是const类型,
    • 赋值过程会改变引用或者const变量的值,所以默认拷贝赋值函数不能被生成
    • 引用的值定义的时候必须被初始化,且以后不能改变指向;
  • 如果父类中的拷贝赋值是私有的,继承的子类也不会生成默认拷贝赋值函数
    • (条款12会详细介绍)
template<typename T>
class NameObject {
public:
    NameObject(std::string& name, const T& value) : nameValue(name), objectValue(value) { }
private:
    std::string& nameValue;
    const T objectValue;
};

#include "item_05.h"
int main() {
    std::string name_obj1("obj1");
    std::string name_obj2("obj2");
    NameObject<int> nobj1(name_obj1, 5);
    NameObject<int> nobj2(name_obj2, 10);
    nobj1 = nobj2;
    return 0;
}

/*
 * 错误信息
main.cpp: In function ‘int main()’:
main.cpp:14:13: error: use of deleted function ‘NameObject<int>& NameObject<int>::operator=(const NameObject<int>&)’
   14 |     nobj1 = nobj2;
      |             ^~~~~
In file included from main.cpp:3:
item_05.h:18:7: note: ‘NameObject<int>& NameObject<int>::operator=(const NameObject<int>&)’ is implicitly deleted because the default definition would be ill-formed:
   18 | class NameObject {
      |       ^~~~~~~~~~
item_05.h:18:7: error: non-static reference member ‘std::string& NameObject<int>::nameValue’, can’t use default assignment operator
item_05.h:18:7: error: non-static const member ‘const int NameObject<int>::objectValue’, can’t use default assignment operator
*/

Item06 若不想使用编译器自动生成的函数,就应该明确拒绝

场景:对于中介买的房子是独一无二的,为这样的资产提供副本毫无意义

  • 版本1
    • 将拷贝构造和拷贝赋值函数设置为私有
    • 但如果成员函数和友元函数访问,不会出现编译问题,会出现链接错误
  • 版本2
    • 将报错提前到编译期
    • 子类调用拷贝构造时会调用父类的拷贝构造,会被编译器拒绝
    • 会造成多重继承(见条款40)
  • 版本3
    • C++11新特性,解决上述问题
#ifndef __ITEM_06_H__
#define __ITEM_06_H__

#include <string>
#include <iostream>
// 版本1
// class HomeForSale {
// public:
//     HomeForSale() {}
// private:
//     HomeForSale(const HomeForSale&);
//     HomeForSale& operator=(const HomeForSale&);
// };

// 版本2
class Uncopyable {
protected:
    Uncopyable() {}
    ~Uncopyable() {}
private:
    Uncopyable(const Uncopyable&);
    Uncopyable& operator=(const Uncopyable&);
};
class HomeForSale : public Uncopyable {};

// 版本3 c++11新特性
class HomeForSale {
public:
    HomeForSale() {}
    HomeForSale(const HomeForSale&) = delete;
    HomeForSale& operator=(const HomeForSale&) = delete;
};

#endif

/*
 * 版本1 报错
main.cpp:20:22: error: ‘HomeForSale::HomeForSale(const HomeForSale&)’ is private within this context
   20 |     HomeForSale h3(h1);
      |                      ^
In file included from main.cpp:4:
item_06.h:10:5: note: declared private here
   10 |     HomeForSale(const HomeForSale&);
      |     ^~~~~~~~~~~
*/

/*
 * 版本2报错
main.cpp:20:22: error: use of deleted function ‘HomeForSale::HomeForSale(const HomeForSale&)’
   20 |     HomeForSale h3(h1);
      |                      ^
In file included from main.cpp:4:
item_06.h:22:7: note: ‘HomeForSale::HomeForSale(const HomeForSale&)’ is implicitly deleted because the default definition would be ill-formed:
   22 | class HomeForSale : public Uncopyable {};
      |       ^~~~~~~~~~~
item_06.h:22:7: error: ‘Uncopyable::Uncopyable(const Uncopyable&)’ is private within this context
item_06.h:19:5: note: declared private here
   19 |     Uncopyable(const Uncopyable&);
*/

/*
 * 版本3报错
main.cpp:20:22: error: use of deleted function ‘HomeForSale::HomeForSale(const HomeForSale&)’
   20 |     HomeForSale h3(h1);
      |                      ^
In file included from main.cpp:4:
item_06.h:27:5: note: declared here
   27 |     HomeForSale(const HomeForSale&) = delete;
*/

文章来源:https://blog.csdn.net/GouDanAndOcean/article/details/135716629
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。