简体   繁体   中英

C++ unordered_map initialization read access violation

I have a struct:

struct Foo
{
    std::unordered_map<std::string, std::string> info;
    int count;
    int bar;
}

I am trying to initialize this struct on the heap as follows:

Foo* createFoo(int count, int bar)
{
    Foo* foo = (Foo*)malloc(sizeof(Foo));
    foo->info = std::unordered_map<std::string, std::string>(); // <- exception thrown here
    foo->count = count;
    foo->bar = bar;
    return foo;
}

I am getting the following exception thrown upon construction of the unordered_map :

Exception thrown: read access violation. _Pnext was 0xCDCDCDD1.

I understand that MVS fills heap allocated memory with 0xCD which is why the _Pnext pointer has this value, but I don't understand why the unordered_map constructor isn't zero-ing these fields out.

I realize that the modern C++ way of doing this is with new /constructors but I am trying to write this code in a non-OOP procedural way with (basically) POD objects.

Am I initializing the map incorrectly?

AC call of malloc

Foo* foo = (Foo*)malloc(sizeof(Foo));

does not invoke constructors for data members.

So the data member

std::unordered_map<std::string, std::string> info;

was not constructed.

And this statement with the copy assignment operator

foo->info = std::unordered_map<std::string, std::string>();

results in undefined behavior because there is not created the object foo->info .

You have to use the operator new instead of malloc.

For example

Foo* foo = new Foo();

malloc() do not initialize allocated memory and this is bad when allocating objects that have non-trivial constructors.

You should use new instead.

Foo* foo = new Foo;

To deallocate objects allocated via new , you can use delete .

delete pointe_to_object;

malloc() doesn't create any object. It just reserves some uninitialized memory. There are no objects in that memory, those would have to be created with placement new .

Now, operator= requires an existing object, because it's a member function (always). By calling this operator on line foo->info = std::unordered_map<std::string, std::string>() you call operator on non-existing object.

The solution is to not go against the language and use new as you are supposed to:

Foo* createFoo(int count, int bar)
{
    Foo* foo = new Foo;
    // unnecessary now, the object is already constructed and default-initialized
    // foo->info = std::unordered_map<std::string, std::string>(); 

    // ints are constructed, but not initialized
    foo->count = count;
    foo->bar = bar;
    return foo;
}

You could also use malloc with placement new , but that's only useful if you need memory without actual objects (eg in vector implementation).


Note: it's a bad smell to use raw new in modern C++ (well, 9 years old, but as modern as std::unordered_map ). Use smart pointers and STL containers instead.

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