The rule of three/five/zero

2021-09-05  本文已影响0人  greatseniorsde

一个例子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;
}



}
    *_image = *source._image; // deep copy

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

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

上一篇下一篇

猜你喜欢

热点阅读