被classes的向量混淆:"The Big Three",在push_back之后删除一个class,以及资源管理

Confused by vectors of classes: "The Big Three", deleting a class after a push_back, and resource management

我有一个 class 这样的:

class cSerialMessage
{
    public:
        cSerialMessage(const enumMessages type, std::string txmessage = "") {rxAnswer="";};

        // Get/Set Methods
        // ...
        bool AddIntParam();     // Stores an int as parameter for the message
        void BuildCompleteMessage() // Build the whole message following the protocol rules

    private:
        enumMessages m_type;
        std::string m_txmessage, m_rxanswer;
        // [...]
};

然后我有另一个 class 其中 "manages" 消息队列:

class cMsgManager
{
    public:
        cMsgManager();

        // [...]
        cSerialMessage* NewMessage(eMessages MSG);
        bool AddParameter(int Param);
        bool QueueMessage(bool FirstPosition);

    private:
        deque<cSerialMessage> cMS;
        cSerialMessage* tempMsg;
}

相关部分是创建 cSerialMessage 并将其添加到双端队列的地方。

cSerialMessage* cMsgManager::NewMessage (eMessages MSG)
{
    // Begin the creation of a new message


    if (tempMsg!=nullptr) {
        // there was already a temporary message
        OutputDebugString ("NOPE!");
        return nullptr;
    }
    tempMsg = new cSerialMessage(MSG);
    return tempMsg;
}
//------------------------------------------------------------------------------
bool cMsgManager::AddParameter (int Param)
{
    if (tempMsg==nullptr) {
        // this means that NewMessage() was'nt called before.
        OutputDebugString ("NOPE!);
        return false;
    }
    return tempMsg->AddIntParam(Param);
}
//------------------------------------------------------------------------------
bool cMsgManager::QueueMessage(bool FirstPosition)
{
    if (tempMsg==nullptr) {
        // this means that NewMessage() was'nt called before.
        OutputDebugString ("NOPE!);
        return false;
    }

    // Build the final message
    tempMsg->BuildCompleteMessage();

    if (FirstPosition) {
        cMS.push_front(*tempMsg);
    }else{
        cMS.push_back(*tempMsg);
    }

    delete tempMsg;

    tempMsg=nullptr;
    return true;
}

尽管有很多关于这个主题的问题 (this is very detailed),我仍然很困惑。

我应该删除我的 tempMsg 吗?它是在双端队列中复制的,还是最终由 tempMsg 指向的数据是稍后从双端队列访问的数据? 或者我必须创建复制构造函数和复制赋值运算符吗?

我应该删除 tempMsg 吗?是的,你创建了它,必须有人删除它,那应该是你。

是否复制到双端队列中?不是,tempMsg指向的东西被复制到双端队列中,但是tempMsg之后还在,它指向的对象还在,所以需要删除。

我是否必须创建复制构造函数和复制赋值运算符?是的,或者如果您对 cMsgManager 不可复制感到满意,则将它们标记为已删除。

  1. Should i delete my tempMsg?

是的,如所写,您必须 delete 您的 tempMsg,或者在程序的生命周期中重复使用单个实例(在第一个实例之后不创建 new 个实例)。重用它可能需要在每次重用之前将其清除,这似乎不值得。

  1. Is it copyed in the deque or, in the end, the data pointed by tempMsg are the one that will be later accessed from the deque?

已复制; push_back 接收引用,但仅记录为复制或移动(并且由于您传递了一个左值,它将进行复制)。您可以通过执行 cMS.push_front(std::move(*tempMsg)); 来清空 tempMsg 来节省一些工作(因为您将在之后删除它,所以您也可以保存副本)。

  1. Or have i to create the copy-constructor and copy-assignement operator?

假设你的 cSerialMessage 的所有成员本身都是可正确复制的(没有原始指针等),并且你没有定义任何自定义 copy/move 操作或析构函数,你应该没问题;编译器生成的复制构造函数可以正常工作。另一方面,cMsgManager 需要完整的 3/5 构造函数和析构函数规则,因为您没有为 tempMsg.

使用智能指针或值语义

请注意,整个动态分配是 pointless/wasteful。您可以将 tempMsg 设为 cSerialMessage(而不是 cSerialMessage*),然后按值使用它。您可以将它保留为实例的一个属性,或者只使用 NewMessage return 实际的新消息,根本不在本地存储副本。本地副本将使线程或可重入代码成为噩梦,因此 return 按值获取新消息,并让 调用者 管理它可能是一个更好的主意。