美文网首页
The rule of three/five/zero

The rule of three/five/zero

作者: greatseniorsde | 来源:发表于2021-09-05 07:58 被阅读0次

    一个例子Chatbot:

    #ifndef CHATBOT_H_
    #define CHATBOT_H_
    
    #include <wx/bitmap.h>
    #include <string>
    
    class GraphNode; // forward declaration
    class ChatLogic; // forward declaration
    
    class ChatBot
    {
    private:
        wxBitmap *_image; // avatar image
        GraphNode *_rootNode;
        ChatLogic *_chatLogic;
    
    public:
        // constructors / destructors
        ChatBot();                     // constructor WITHOUT memory allocation
        ChatBot(std::string filename); // constructor WITH memory allocation
        ~ChatBot();
    
     
        ChatBot(const ChatBot &source); // copy constructor
        ChatBot &operator=(const ChatBot &source); // copy assignment operator
        ChatBot(ChatBot &&source); // move constructor
        ChatBot &operator=(ChatBot &&source); //  move assignment operator
     
    };
    
    #endif /* CHATBOT_H_ */
    
    #include <iostream>
    #include <random>
    #include <algorithm>
    #include <ctime>
    
    #include "chatlogic.h"
    #include "graphnode.h"
    #include "graphedge.h"
    #include "chatbot.h"
    
    // constructor WITHOUT memory allocation
    ChatBot::ChatBot()
    {
        // invalidate data handles
        _image = nullptr;
        _chatLogic = nullptr;
        _rootNode = nullptr;
    }
    
    // constructor WITH memory allocation
    ChatBot::ChatBot(std::string filename)
    {
        std::cout << "ChatBot Constructor" << std::endl;
        
        // invalidate data handles
        _chatLogic = nullptr;
        _rootNode = nullptr;
    
        // load image into heap memory
        _image = new wxBitmap(filename, wxBITMAP_TYPE_PNG);
    }
    
    ChatBot::~ChatBot()
    {
        std::cout << "ChatBot Destructor" << std::endl;
    
        // deallocate heap memory
        if(_image != NULL) // Attention: wxWidgets used NULL and not nullptr
        {
            delete _image;
            _image = NULL;
        }
    }
    ChatBot::ChatBot(const ChatBot &source) // 2 : copy constructor
    {
        std::cout << "ChatBot Copy Constructor" << std::endl;
        _rootNode = source._rootNode;
        _chatLogic = source._chatLogic;
        _image = source._image;
    }
    
    
    ChatBot& ChatBot::operator=(const ChatBot &source) // 3 : copy assignment operator
    {
        std::cout << "ChatBot Copy Assignment" << std::endl;
        if (this == &source)
            return *this;
        _rootNode = source._rootNode;
        _chatLogic = source._chatLogic;
        _image = source._image;
        return *this;
    }
    
    ChatBot::ChatBot(ChatBot &&source) // 4 : move constructor
    {
        std::cout << "ChatBot Move Constructor " << this << std::endl;
        _image = source._image;
        _chatLogic = source._chatLogic;
        _chatLogic->SetChatbotHandle(this);
        _rootNode = source._rootNode;
        source._image = nullptr;
        source._chatLogic = nullptr;
        source._rootNode = nullptr;
    }
    
    ChatBot& ChatBot::operator=(ChatBot &&source) // 5 : move assignment operator
    {
        std::cout << "ChatBot Move Assignment Operator " << this << std::endl;
        if (this == &source)
            return *this;
    
        delete _image;
    
        _image = source._image;
        _chatLogic = source._chatLogic;
        _chatLogic->SetChatbotHandle(this);
        _rootNode = source._rootNode;
    
        source._rootNode = nullptr;
        source._image = nullptr;
        source._chatLogic = nullptr;
    
        return *this;
    }
    
    
    
    }
    
    • Copy constructors/assignment:
      Copy constructors are used to initialize a class by making a copy of an object of the same class. Copy assignment is used to copy one class to another existing class. By default, C++ will provide a copy constructor and copy assignment operator if one is not explicitly provided. These compiler-provided functions do shallow copies, which may cause problems for classes that allocate dynamic memory. So classes that deal with dynamic memory should override these functions to do deep copies.
      所以这里的copy constuctor/assignment里对于_image的copy是shallow copy, 只是复制了指针,而没有复制指针指向的address上的数据
      You need to use a deep copy here.A deep copy copies all fields and makes copies of dynamically allocated memory pointed to by the fields.
        *_image = *source._image; // deep copy
    

    浅拷贝导致的结果是可能在call dtor的时候两次destroy同一内存地址的数据
    对于这类问题的解决办法一是自己定义deep copy in copy constructor/assignment, 也有人会直接禁用copy constructor/assignment, 于是我看到了这篇文章:
    为什么很多人禁用拷贝(复制)构造函数

    • The rule of three/five/zero
      According to CppCoreGuidelines:

    C.20: If you can avoid defining default operations, do

    C.21: If you define or =delete any copy, move, or destructor function, define or =delete them all

    Back to Basics: RAII and the Rule of Zero - Arthur O'Dwyer - CppCon 2019

    相关文章

      网友评论

          本文标题:The rule of three/five/zero

          本文链接:https://www.haomeiwen.com/subject/yxwlwltx.html