Saya mendapatkan masalah kebocoran memori di salah satu aplikasi saya yang sedang saya lalui dan coba perbaiki. Salah satu titik masalah yang saya curigai adalah di mana saya mengurai baris dari file menjadi perintah menggunakan BNFC:

void LineStreamScriptProvider::populateQueue()
{
    if(shouldPopulate())
    {
        TasScript::ShowAbsyn shower;
        std::string line;
        while(queueSize() < 30 && !stream.eof())
        {
            std::getline(stream, line);
            const char* lineCStr = line.c_str();
            TasScript::Program* lineCmds = TasScript::pProgram(lineCStr);
            TasScript::P* asLeaf = static_cast<TasScript::P*>(lineCmds);
            TasScript::ListCommand* cList = asLeaf->listcommand_;
            for_each(cList->begin(), cList->end(), [this, shower](TasScript::Command* cmd) {
                // log_to_sd_out("Parsed command %s\n", shower->show(cmd));
                std::shared_ptr<TasScript::Command> cmdShared(cmd);
                pushToQueue(cmdShared);
            });
        }
        if(stream.eof())
        {
            afterEOF();
        }
    }
}

Sebagai referensi:

class P : public Program
{
public:
  ListCommand *listcommand_;
// ...
class ListCommand : public Visitable, public std::vector<Command*>
{
// ...

BNFC membangun ini dengan new dan kemudian mengembalikan pointer. Apakah aman untuk delete lineCmds tanpa menghapus nilai yang dipegang oleh cmdShared?

0
Aly 15 Maret 2020, 06:19

1 menjawab

Jawaban Terbaik

Maaf, saya tidak mengetahui BNFC dan itu membuat petunjuk mentah untuk Anda.

Apakah aman menghapus lineCmds tanpa menghapus nilai yang dipegang oleh cmdShared?

Jika Anda membuat penunjuk bersama dari penunjuk mentah, penunjuk bersama mengambil kepemilikan atas sumber daya itu. Pointer bersama akan mempertahankan jumlah referensi untuk sumber daya itu hingga turun ke nol, yaitu ketika semua penunjuk bersama untuk sumber daya itu keluar dari cakupan, pada titik mana ia akan mencoba untuk menghancurkan sumber daya.

Di sini Anda membuat pointer bersama dan meneruskannya ke antrian:

std::shared_ptr<TasScript::Command> cmdShared(cmd);
pushToQueue(cmdShared);

Pointer bersama akan menangani manajemen memori untuk Anda. Jadi tidak perlu secara eksplisit memanggil delete pada vektor perintah. Setelah semua pointer bersama tipe std::shared_ptr<TasScript::Command> dihancurkan, sumber daya juga dihancurkan.

Jadi tidak, tidak aman untuk menghapus vektor pointer dalam kasus ini.


Solusi lain yang lebih sederhana adalah dengan mengambil salinan TasScript::Command:

TasScript::Command cmdCopy(*cmd);

Kemudian ubah pushToQueue() untuk menerima dengan const TasScript::Command&, bukan dengan penunjuk bersama. Maka Anda tidak perlu khawatir tentang penunjuk yang dihancurkan karena Anda memiliki salinan nilainya.

Sepertinya di loop sementara Anda, Anda membocorkan memori. Bukankah Anda harus menghapus lineCmds dan cList?

1
jignatius 18 Maret 2020, 09:21