I have a very simple piece of code with 2 structures and one dynamic allocation. The program crashes on the "nume" initialization.
typedef struct{
int key;
string name;
} TElement;
typedef struct nod {
int cheie;
string nume;
struct nod *stg, *dr;
} NOD;
when i try to do this
void ABC::inserare_element(TElement e){
NOD *p, *q;
int n;
/* construction nod p*/
n=sizeof (NOD);
p=(NOD*)malloc(n);
p->cheie = e.key;
p->nume = e.name; // on this line the program crashes
Thanks
malloc() will not invoke the constructor of NOD, meaning the constructor of nume will not have been invoked resulting in an attempt to use std::string::operator= on an unconstructed/uninitialized std::string: use new.
You have a hot mix here of high-level C++ objects, such as std::string and C-style memory allocations such as malloc. The thing is that C++'s new operator not only allocates memory, but also calls constructor of high-level objects. The problem you are facing is that nume object of type std::string is not initialized properly, thus you run into undefined behavior that leads to a crash. That is because you are lucky. It could have been a lot worse if program was actually working, but producing strange, unexpected results.
To make it work like you want, you can simply use new instead of malloc. For example:
p = new NOD;
If it so happens that you really need to use malloc or other memory management API that does not care about C++ objects, then you have to call a constructor of nume manually, using a placement new. For example:
p = (NOD*)malloc(n);
new ((void *)&p->nume) std::string();
In case you go that way - don't forget to call destructor as well or you will end up with a memory leak.
You should use new instead of malloc. malloc is a C function and it only allocates a chunk of memory. Using new will call the default constructor of your class, and the string constructor will also be called at this moment.
Related
As such:
class MyClass{
public:
int *property;
MyClass(){
property = (int*)malloc(sizeof(int));
}
~MyClass(){
free(property);
}
};
I understand that there are better ways to do this, but I don't think I understand why exactly this is incorrect.
Would there ever be a reason to initialize a pointer in a constructor with malloc?
At least couple of reasons comes to my mind:
you need to work with C code/library and pass pointer there that expected to be initialized by malloc()
You are limited with resources and want to be able to use realloc() with it
There could be more, but you need to be careful when working with raw pointers, either initialized by new or malloc(). For example your class violates rule of 3/5/0. Best way to handle that - use a smart pointer.
Also you need to remember that with malloc() you need to be sure that memory is properly initialized, it can be done with memset() or simple assignments with POD types or (and this is mandatory for non POD) through placement new. That usage is not trivial so you would want to deal with that when you really need it.
In general you should use new not malloc in c++ code. The only time not to do that is in extreme corner cases where you want to control exact location for some reason, building custom memory pools (and even then you should overload new so as not to call malloc directly in the class definition). In that case you use 'placement new'
The main reason to use new is that it will correctly construct the object that it just made. malloc will return garbage memory. Not relevant (maybe) for ints but certainly important for objects
You have to make sure to disable copy constructor/assignment operator which are generated by default in c++. If you don't, you will have undefined behavior. E.g. Below code will destruct twice.
#include<cstdlib>
static int number_of_constructions = 0;
static int number_of_destructions = 0;
struct S {
int * p;
S() {
p = (int*) malloc(sizeof(int));
number_of_constructions++;
}
~S() {
free(p);
number_of_destructions++;
}
};
void foo() {
S s;
S s2 = s;
}
Link: https://godbolt.org/g/imujg1
I have the following structure:
struct node{
char name;
vector<node*> children;
void addChild(char name){
node *newChild = (node*)malloc(sizeof(node));
newChild->name = name;
children.push_back(newChild);
}
};
The code above compiles but crashes with a std::bad_alloc prompt whenever addChild is called for any node that was created using addChild.
It seems to me like i should somehow be allocating memory for the vector as well, but i am unsure about how i would go about doing that.
I am a "begginer" and know very little about memory allocation so any help would be appreciated.
Thanks in advance.
Don't use malloc and free in C++. Especially for objects that needs to have their constructor called, since malloc does not call the constructor.
In your case it means that the std::vector constructor will not be called, and you will have undefined behavior when you use the vector.
Use new and delete instead.
Any good beginners book should have told you this.
my node contains an int and a string variable, and I tried using binary search tree. the code is as follow:
struct node{
int a;
string members[5];
};
int main(){
node * root = NULL;
root = (node*)malloc(sizeof(node));
root->members[0] = "aaaaa";
return 0;
}
of course, my code wasn't exactly like that, I made it short in main because I want to show just the problem. it gave me 'access violation writing location'. I tried using 'new node();' instead of malloc and that didn't happen. why is this exactly?
malloc() only allocates memory. It doesn't call the constructor of the object. You could call the constructor on allocated memory using, e.g.
void* mem = malloc(sizeof(node));
if (mem) {
node* root = new(mem) node;
// ...
}
When using new node instead of malloc(sizeof(node) the allocate memory also gets initialized. Using an uninitialized object is undefined behavior.
malloc only allocates raw storage. new allocates raw storage and initializes it to contain a specified type.
If you're allocating only POD types, that distinction is mostly one of wording, with little real difference in what happens.
If you're allocating something like an std::string that has a constructor, there's a world of difference though. If you use new, then your string variables have all been initialized so they're real (albeit, still empty) strings. When you just use malloc, they haven't been initialized at all--they're just chunks of uninitialized raw storage the right size to contain a string. When you try to use them as a string, a quick crash is about the best you can hope for.
So given this simple scenario:
class A{
public:
A(){
n = new int(10);
}
~A(){
delete n;
}
int* n;
};
int main(){
A* a = new A();
}
Can this cause heap corruption (problems in general), since a-pointer hasn't finished allocating, while I'm making a new allocation?
If so, using std::vector inside heap constructors in also prohibited, right?
Thank you.
Your a pointer has finished allocating.
New works as follows (oversimplified)
Allocate
Construct
So in your case
Allocate A
Construct A
Allocate int
Construct int - initialize
Finish Construct A
This ignores cases involving exceptions..
There is no such thing as a "heap constructor", and no, you cannot corrupt the heap by newing memory inside a constructor of an object on the heap. The memory for the new A is fully allocated at the time A::A() is invoked. What you're doing is both correct and extremely common. Your constructor need never be concerned with whether the object being constructed is allocated on the stack or heap. Otherwise, pointers and classes would be pretty useless.
if "new" throw an exception then the object is not allocated (beware any allocation made BEFORE "new" need to be deallocated else you'll have a memory leach)..
Exceptions are thinked to be used as error system since constructor can't return a error code.
myclass::myclass()
{
param1 = new type1(); //successfull
try
{
param2= new type2(); //may fail
}
(...)
{
delete param1; //need to deallocate
}
}
That's a bit overkill, I prefer to have no exceptions in constructors at all, some people make entire frameorks with constructors than can throw exceptions..
anyway any other bug in the allocator can cause:
segmentation fault (access out-of-range value)
heap corruption (overwrite data that is in memory range but that is not tecnically owned bythe object)
infinite loop (you need to abort the program externally or it will never exit the allocator).
Those are the mains problem that you can also have with normal code of course. The default allocator however will not give any problem, at least can throw a "out of memory" exception. if you not have enough ram.
I've a situation like the following, and I'm not sure whether or not the std::string elements of the struct leak memory or if this is ok. Is the memory allocated by those two std::strings deleted when free(v) is called?
struct MyData
{
std::string s1;
std::string s2;
};
void* v = malloc(sizeof(MyData));
...
MyData* d = static_cast<MyData*>(v);
d->s1 = "asdf";
d->s2 = "1234";
...
free(v);
Leak or not?
I'm using the void-pointer because I have another superior struct, which consists of an enum and a void-pointer. Depending on the value of the enum-variable, the void* will point to different data-structs.
Example:
enum-field has EnumValue01 => void-pointer will point to a malloc'd MyData01 struct
enum-field has EnumValue02 => void-pointer will point to a malloc'd MyData02 struct
Suggestions for different approaches are very appreciated, of course.
You shouldn't be using malloc() and free() in a C++ program; they're not constructor/destructor-aware.
Use the new and delete operators.
That's undefined behavior - memory allocated by malloc() in uninitialized, so using it as a struct containing string objects can lead to anything; I'd expect crashing. Since no-one invokes the destructor before calling free(), string objects won't be destroyed and their buffers will almost definitely leak.
There is a leak indeed. free doesn't call MyData destructor (after all it's a C function which doesn't know anything about C++ stuff). Either you should use new/delete instead of malloc/free:
MyData* d = new MyData;
d->s1 = "asdf";
d->s2 = "1234";
delete d;
or call destructor by yourself:
void* v = malloc(sizeof(MyData));
MyData* d = new (v) MyData; // use placement new instead of static_cast
d->s1 = "asdf";
d->s2 = "1234";
...
d->~MyData();
free(v);
as sharptooth noted you can't directly use memory allocated by malloc as a MyData struct without initialization, so you have to do it by yourself as well. To initialize MyData using already allocated memory you need to use placement new (see in the code above).
Yes, because the constructor and destructor are not called. Use new and delete.
Even if you manage to initialize s1 and s2 properly, simply doing free(d) won't reclaim any memory dynamically allocated for s1 and s2. You should really create *d through new and destroy through delete, which will ensure proper destruction of s1 and s2 (and initialization as well).
Yes, you are probably leaking, and your strings aren't properly constructed, either. The program's behaviour is undefined, meaning everything is going to go wrong.
The closest valid way to do what you're doing is placement new. Still, you'd be better off with some common base class and proper C++ polymorphism.
If the possible types are unrelated, you can use Boost.Any or Boost.Variant.