简体   繁体   中英

C++ double free or corruption (out)

Here is my code:

#include "Accounts.h"

using namespace Vibranium;

void Accounts::LoadTable(RowResult &res) {

        std::vector<AccountsStruct> accounts;
        AccountsStruct accountsStruct;
        for (Row row : res.fetchAll()){
            accountsStruct.id = row[0].get<int>();
            accountsStruct.email = row[1].get<std::string>();
            accountsStruct.warTag = row[2].get<std::string>();
            accountsStruct.state = row[4].get<int>();
            accountsStruct.name = row[5].get<std::string>();
            accountsStruct.lastname = row[6].get<std::string>();
            accountsStruct.country = row[7].get<std::string>();
            accountsStruct.dob_month = row[8].get<int>();
            accountsStruct.dob_day = row[9].get<int>();
            accountsStruct.dob_year = row[10].get<int>();
            accountsStruct.balance = row[11].get<double>();
            accountsStruct.created_at = row[12].get<std::string>();
            accountsStruct.updated_at = row[13].get<std::string>();
            accountsStruct.account_role = row[15].get<int>();
            accountsStruct.rank = row[16].get<int>();
            accountsStruct.playerRole = row[17].get<int>();
            Data.emplace_back(&accountsStruct);
        }

    std::cout << "SIZE: " << Data.size() << std::endl;

}

Data is std::vector<std::unique_ptr<DataStruct>> Data; .

To add into the vector I call Data.emplace_back(&accountsStruct); which leads me to the following output:

SIZE: 2
double free or corruption (out)

Process finished with exit code 134 (interrupted by signal 6: SIGABRT)

I am sure this line Data.emplace_back(&accountsStruct); is causing the issue. Why? How can I fix it?

You're trying to free memory not allocated with new (stack memory, to be precise).

std::vector<std::unique_ptr<DataStruct>> Data;

AccountsStruct accountsStruct;   // <-- a stack variable

Data.emplace_back(&accountsStruct); // <-- an instance of unique_ptr is created using the address of accountsStruct

So when Data is destroyed, unique_ptr calls delete on that pointer (not good!!).

I can think of 2 possible solutions:

  1. Allocate accountsStruct on the heap using std::make_unique :

     for (auto& row : res.fetchAll()) { Data.emplace_back(std::make_unique<AccountsStruct>()); // allocate a new instance on the heap AccountsStruct& accountsStruct = *Data.back(); // get a reference to that instance accountsStruct.id = row[0].get<int>(); // fill it normally ... accountsStruct.email = row[1].get<std::string>(); accountsStruct.warTag = row[2].get<std::string>(); . . .
  2. Simplify Data to store by-value: std::vector<DataStruct> Data;

     for (auto& row : res.fetchAll()) { Data.emplace_back(); // allocates a new instance of AccountsStruct in-place AccountsStruct& accountsStruct = Data.back(); // get a reference to that instance accountsStruct.id = row[0].get<int>(); // fill it normally ... accountsStruct.email = row[1].get<std::string>(); accountsStruct.warTag = row[2].get<std::string>(); . . .

Data should contain a std::unique_ptr<AccountsStruct> . I'm afraid, unique_ptr can't be created from AccountsStruct.

So, create struct dynamically, fills by data, create unique_ptr from pointer and add it to vector.

The problem in your code is that you provide an address of a local variable to the constructor of std::unique_ptr.

I assume that Data is std::vector<std::unique_ptr<AccountsStruct>> If AccountsStruct has constructor with no arguments, you can try this:

#include "Accounts.h"

using namespace Vibranium;

void Accounts::LoadTable(RowResult &res) {

        std::vector<AccountsStruct> accounts;
        
        // create an instance in the vector and get a reference to it
        // auto will be std::unique_ptr<AccountsStruct>&;
        auto &accountsStruct = Data.emplace_back();
        
        // work with that reference
        for (Row row : res.fetchAll()){
            accountsStruct->id = row[0].get<int>();
            accountsStruct->email = row[1].get<std::string>();
            accountsStruct->warTag = row[2].get<std::string>();
            accountsStruct->state = row[4].get<int>();
            accountsStruct->name = row[5].get<std::string>();
            accountsStruct->lastname = row[6].get<std::string>();
            accountsStruct->country = row[7].get<std::string>();
            accountsStruct->dob_month = row[8].get<int>();
            accountsStruct->dob_day = row[9].get<int>();
            accountsStruct->dob_year = row[10].get<int>();
            accountsStruct->balance = row[11].get<double>();
            accountsStruct->created_at = row[12].get<std::string>();
            accountsStruct->updated_at = row[13].get<std::string>();
            accountsStruct->account_role = row[15].get<int>();
            accountsStruct->rank = row[16].get<int>();
            accountsStruct->playerRole = row[17].get<int>();                
        }

    std::cout << "SIZE: " << Data.size() << std::endl;
}

If AccountsStruct is derived from DataStruct you can use:

data.emplace_back(std::make_unique<AccountData>());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM