如何避免这种内存泄漏?
How to avoid this memory leak?
这是我的代码:
void MIDITest::CreateNoteBlock() {
IMidiMsgExt* midiMessage = new IMidiMsgExt;
midiMessage->MakemidiMessageMsg(57, 100, 0, 0, 0);
queuedNotes.insert(*midiMessage);
midiMessage = new IMidiMsgExt;
midiMessage->MakemidiMessageMsg(60, 100, 0, tickSize * 38, 0);
queuedNotes.insert(*midiMessage);
midiMessage = new IMidiMsgExt;
midiMessage->MakemidiMessageMsg(62, 100, 0, 0, 0);
queuedNotes.insert(*midiMessage);
midiMessage = new IMidiMsgExt;
midiMessage->MakemidiMessageMsg(65, 100, 0, tickSize * 32, 0);
queuedNotes.insert(*midiMessage);
midiMessage = new IMidiMsgExt;
midiMessage->MakemidiMessageMsg(57, 0, tickSize * 111, 0);
queuedNotes.insert(*midiMessage);
midiMessage = new IMidiMsgExt;
midiMessage->MakemidiMessageMsg(60, 0, tickSize * 111, 0);
queuedNotes.insert(*midiMessage);
midiMessage = new IMidiMsgExt;
midiMessage->MakemidiMessageMsg(62, 0, tickSize * 75, 0);
queuedNotes.insert(*midiMessage);
midiMessage = new IMidiMsgExt;
midiMessage->MakemidiMessageMsg(65, 0, tickSize * 105, 0);
queuedNotes.insert(*midiMessage);
}
所以在每个 new
运算符处,它都会分配一块内存。
我应该在 queuedNotes 中的任何 insert
之后使用 free
吗?还是在void
函数return之后发布? (即CreateNoteBlock的括号)
或者我可以 "reuse" 每次 midiMessage
指针指向一个新的 IMidiMsgExt
?
答案是根本不用new
。创建具有自动存储持续时间的对象
IMidiMsgExt midiMessage;
然后您可以继续调用 MakemidiMessageMsg
并将消息的副本插入 multiset
。
midiMessage.MakemidiMessageMsg(57, 100, 0, 0, 0);
queuedNotes.insert(midiMessage);
midiMessage.MakemidiMessageMsg(60, 100, 0, tickSize * 38, 0);
queuedNotes.insert(midiMessage);
//...
现在 multiset
拥有所有消息的副本,并且在函数结束时 midiMessage
被销毁,不需要进行内存管理。
如果 IMidiMsgExt
有一个类似于 MakemidiMessageMsg
的构造函数,您可以在其中构建完整的消息,那么您可以进一步简化它并使用类似
的东西
queuedNotes.insert(IMidiMsgExt(57, 100, 0, 0, 0));
queuedNotes.insert(IMidiMsgExt(60, 100, 0, tickSize * 38, 0));
现在我们甚至不需要 midiMessage
。
您有 Java 或 C# 背景吗?在 C++ 中,您不必使用 new
来创建对象,只需声明它们即可:
IMidiMsgExt midiMessage;
midiMessage.MakemidiMessageMsg(57, 100, 0, 0, 0);
queuedNotes.insert(midiMessage);
要么是这样(这是我推荐的解决方案),要么您必须显式释放对象:
IMidiMsgExt* midiMessage = new IMidiMsgExt;
midiMessage->MakemidiMessageMsg(57, 100, 0, 0, 0);
queuedNotes.insert(*midiMessage);
delete miniMessage;
使用 new 动态分配 IMidiMsgExt
似乎是多余的。你可以直接在堆栈上分配它(没有指针),然后它会在你的方法returns时被销毁。即:
void MIDITest::CreateNoteBlock() {
IMidiMsgExt midiMessage();
midiMessage.MakemidiMessageMsg(57, 100, 0, 0, 0);
queuedNotes.insert(midiMessage);
midiMessage = IMidiMsgExt();
midiMessage.MakemidiMessageMsg(60, 100, 0, tickSize * 38, 0);
queuedNotes.insert(midiMessage);
midiMessage = IMidiMsgExt();
midiMessage.MakemidiMessageMsg(62, 100, 0, 0, 0);
queuedNotes.insert(midiMessage);
midiMessage = IMidiMsgExt();
midiMessage.MakemidiMessageMsg(65, 100, 0, tickSize * 32, 0);
queuedNotes.insert(midiMessage);
midiMessage = IMidiMsgExt();
midiMessage.MakemidiMessageMsg(57, 0, tickSize * 111, 0);
queuedNotes.insert(midiMessage);
midiMessage = IMidiMsgExt();
midiMessage.MakemidiMessageMsg(60, 0, tickSize * 111, 0);
queuedNotes.insert(midiMessage);
midiMessage = IMidiMsgExt();
midiMessage.MakemidiMessageMsg(62, 0, tickSize * 75, 0);
queuedNotes.insert(midiMessage);
midiMessage = IMidiMsgExt();
midiMessage.MakemidiMessageMsg(65, 0, tickSize * 105, 0);
queuedNotes.insert(midiMessage);
}
尝试让你的 API 更像 C++。
在堆栈中使用一个对象,而不是在堆中创建大量新对象。
void MIDITest::CreateNoteBlock() {
IMidiMsgExt midiMessage;
midiMessage.MakemidiMessageMsg(57, 100, 0, 0, 0);
queuedNotes.insert(midiMessage);
midiMessage.MakemidiMessageMsg(60, 100, 0, tickSize * 38, 0);
queuedNotes.insert(midiMessage);
// ...
}
在构造函数中初始化您的对象。为 IMidiMsgExt
.
定义一个 operator = (const IMidiMsgExt&)
void MIDITest::CreateNoteBlock() {
IMidiMsgExt midiMessage(57, 100, 0, 0, 0);
queuedNotes.insert(midiMessage);
midiMessage = IMidiMsgExt(60, 100, 0, tickSize * 38, 0);
queuedNotes.insert(midiMessage);
// ...
}
我想,insert()
需要 const IMidiMsgExt&
。所以你可以直接传递新初始化的对象:
void MIDITest::CreateNoteBlock() {
queuedNotes.insert({57, 100, 0, 0, 0});
queuedNotes.insert({60, 100, 0, tickSize * 38, 0});
// ...
}
顺便说一句:你应该更喜欢使用例如std::queue<>
queuedNotes
。那么你将不会使用 insert()
,而是 push()
,或 emplace()
。 emplace()
的优点是,它在容器中构造对象,而不是先创建它然后将其复制到容器中:
void MIDITest::CreateNoteBlock() {
queuedNotes.emplace(57, 100, 0, 0, 0);
queuedNotes.emplace(60, 100, 0, tickSize * 38, 0);
// ...
}
您的类型名 IMidiMsgExt
也向我发出信号,表明您正试图在 C++ 中模仿 C# 的思维方式。这是可能的,但通常不是首选解决方案。从你的问题来看,我对你的 class 树和提供建议的基本要求了解不够,但在 C++ 中,这通常是一种代码味道。
这是我的代码:
void MIDITest::CreateNoteBlock() {
IMidiMsgExt* midiMessage = new IMidiMsgExt;
midiMessage->MakemidiMessageMsg(57, 100, 0, 0, 0);
queuedNotes.insert(*midiMessage);
midiMessage = new IMidiMsgExt;
midiMessage->MakemidiMessageMsg(60, 100, 0, tickSize * 38, 0);
queuedNotes.insert(*midiMessage);
midiMessage = new IMidiMsgExt;
midiMessage->MakemidiMessageMsg(62, 100, 0, 0, 0);
queuedNotes.insert(*midiMessage);
midiMessage = new IMidiMsgExt;
midiMessage->MakemidiMessageMsg(65, 100, 0, tickSize * 32, 0);
queuedNotes.insert(*midiMessage);
midiMessage = new IMidiMsgExt;
midiMessage->MakemidiMessageMsg(57, 0, tickSize * 111, 0);
queuedNotes.insert(*midiMessage);
midiMessage = new IMidiMsgExt;
midiMessage->MakemidiMessageMsg(60, 0, tickSize * 111, 0);
queuedNotes.insert(*midiMessage);
midiMessage = new IMidiMsgExt;
midiMessage->MakemidiMessageMsg(62, 0, tickSize * 75, 0);
queuedNotes.insert(*midiMessage);
midiMessage = new IMidiMsgExt;
midiMessage->MakemidiMessageMsg(65, 0, tickSize * 105, 0);
queuedNotes.insert(*midiMessage);
}
所以在每个 new
运算符处,它都会分配一块内存。
我应该在 queuedNotes 中的任何 insert
之后使用 free
吗?还是在void
函数return之后发布? (即CreateNoteBlock的括号)
或者我可以 "reuse" 每次 midiMessage
指针指向一个新的 IMidiMsgExt
?
答案是根本不用new
。创建具有自动存储持续时间的对象
IMidiMsgExt midiMessage;
然后您可以继续调用 MakemidiMessageMsg
并将消息的副本插入 multiset
。
midiMessage.MakemidiMessageMsg(57, 100, 0, 0, 0);
queuedNotes.insert(midiMessage);
midiMessage.MakemidiMessageMsg(60, 100, 0, tickSize * 38, 0);
queuedNotes.insert(midiMessage);
//...
现在 multiset
拥有所有消息的副本,并且在函数结束时 midiMessage
被销毁,不需要进行内存管理。
如果 IMidiMsgExt
有一个类似于 MakemidiMessageMsg
的构造函数,您可以在其中构建完整的消息,那么您可以进一步简化它并使用类似
queuedNotes.insert(IMidiMsgExt(57, 100, 0, 0, 0));
queuedNotes.insert(IMidiMsgExt(60, 100, 0, tickSize * 38, 0));
现在我们甚至不需要 midiMessage
。
您有 Java 或 C# 背景吗?在 C++ 中,您不必使用 new
来创建对象,只需声明它们即可:
IMidiMsgExt midiMessage;
midiMessage.MakemidiMessageMsg(57, 100, 0, 0, 0);
queuedNotes.insert(midiMessage);
要么是这样(这是我推荐的解决方案),要么您必须显式释放对象:
IMidiMsgExt* midiMessage = new IMidiMsgExt;
midiMessage->MakemidiMessageMsg(57, 100, 0, 0, 0);
queuedNotes.insert(*midiMessage);
delete miniMessage;
使用 new 动态分配 IMidiMsgExt
似乎是多余的。你可以直接在堆栈上分配它(没有指针),然后它会在你的方法returns时被销毁。即:
void MIDITest::CreateNoteBlock() {
IMidiMsgExt midiMessage();
midiMessage.MakemidiMessageMsg(57, 100, 0, 0, 0);
queuedNotes.insert(midiMessage);
midiMessage = IMidiMsgExt();
midiMessage.MakemidiMessageMsg(60, 100, 0, tickSize * 38, 0);
queuedNotes.insert(midiMessage);
midiMessage = IMidiMsgExt();
midiMessage.MakemidiMessageMsg(62, 100, 0, 0, 0);
queuedNotes.insert(midiMessage);
midiMessage = IMidiMsgExt();
midiMessage.MakemidiMessageMsg(65, 100, 0, tickSize * 32, 0);
queuedNotes.insert(midiMessage);
midiMessage = IMidiMsgExt();
midiMessage.MakemidiMessageMsg(57, 0, tickSize * 111, 0);
queuedNotes.insert(midiMessage);
midiMessage = IMidiMsgExt();
midiMessage.MakemidiMessageMsg(60, 0, tickSize * 111, 0);
queuedNotes.insert(midiMessage);
midiMessage = IMidiMsgExt();
midiMessage.MakemidiMessageMsg(62, 0, tickSize * 75, 0);
queuedNotes.insert(midiMessage);
midiMessage = IMidiMsgExt();
midiMessage.MakemidiMessageMsg(65, 0, tickSize * 105, 0);
queuedNotes.insert(midiMessage);
}
尝试让你的 API 更像 C++。
在堆栈中使用一个对象,而不是在堆中创建大量新对象。
void MIDITest::CreateNoteBlock() {
IMidiMsgExt midiMessage;
midiMessage.MakemidiMessageMsg(57, 100, 0, 0, 0);
queuedNotes.insert(midiMessage);
midiMessage.MakemidiMessageMsg(60, 100, 0, tickSize * 38, 0);
queuedNotes.insert(midiMessage);
// ...
}
在构造函数中初始化您的对象。为 IMidiMsgExt
.
operator = (const IMidiMsgExt&)
void MIDITest::CreateNoteBlock() {
IMidiMsgExt midiMessage(57, 100, 0, 0, 0);
queuedNotes.insert(midiMessage);
midiMessage = IMidiMsgExt(60, 100, 0, tickSize * 38, 0);
queuedNotes.insert(midiMessage);
// ...
}
我想,insert()
需要 const IMidiMsgExt&
。所以你可以直接传递新初始化的对象:
void MIDITest::CreateNoteBlock() {
queuedNotes.insert({57, 100, 0, 0, 0});
queuedNotes.insert({60, 100, 0, tickSize * 38, 0});
// ...
}
顺便说一句:你应该更喜欢使用例如std::queue<>
queuedNotes
。那么你将不会使用 insert()
,而是 push()
,或 emplace()
。 emplace()
的优点是,它在容器中构造对象,而不是先创建它然后将其复制到容器中:
void MIDITest::CreateNoteBlock() {
queuedNotes.emplace(57, 100, 0, 0, 0);
queuedNotes.emplace(60, 100, 0, tickSize * 38, 0);
// ...
}
您的类型名 IMidiMsgExt
也向我发出信号,表明您正试图在 C++ 中模仿 C# 的思维方式。这是可能的,但通常不是首选解决方案。从你的问题来看,我对你的 class 树和提供建议的基本要求了解不够,但在 C++ 中,这通常是一种代码味道。