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.