如何避免这种内存泄漏?

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++ 中,这通常是一种代码味道。