被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
不可复制感到满意,则将它们标记为已删除。
- Should i delete my tempMsg?
是的,如所写,您必须 delete
您的 tempMsg
,或者在程序的生命周期中重复使用单个实例(在第一个实例之后不创建 new
个实例)。重用它可能需要在每次重用之前将其清除,这似乎不值得。
- 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
来节省一些工作(因为您将在之后删除它,所以您也可以保存副本)。
- 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 按值获取新消息,并让 调用者 管理它可能是一个更好的主意。
我有一个 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
不可复制感到满意,则将它们标记为已删除。
- Should i delete my tempMsg?
是的,如所写,您必须 delete
您的 tempMsg
,或者在程序的生命周期中重复使用单个实例(在第一个实例之后不创建 new
个实例)。重用它可能需要在每次重用之前将其清除,这似乎不值得。
- 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
来节省一些工作(因为您将在之后删除它,所以您也可以保存副本)。
- 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 按值获取新消息,并让 调用者 管理它可能是一个更好的主意。