https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization
There is an example of how RAII works. I always thought that C++ gets this behavior from C. That when you define a variable in a function, that variable becomes invalid when you leave the function. Though maybe the concept has no meaning when there is no object. C does not initialize structs but C++ does. Is that the difference? I am a bit confused.
I always thought that ... That when you define a variable in a function, that variable becomes invalid when you leave the function
You've thought correctly.
You seem to be confused about what RAII is for. It is for management of dynamic resources such as dynamic memory allocations. It relies on language features such a constructors and destructors, which do not exist in C.
The difference is that C++ has constructors and destructors.
C doesn't guarantee anything will be done on scope entrance and exit. If you declare a variable and don't assign anything to it, you can read garbage when you try to read that variable. When you exit a scope, nothing is done to what was on the stack in the scope you just exited.
In C++, trivial types like int behave the same way. With class types (classes, struct, unions), a variable of the type is created with a constructor and destroyed with a destructor. If you declare a variable in a way that calls a non-trivial constructor, then that constructor performs initialization on the variable. If you declare a scoped variable of a type has a non-trivial destructor, that destructor is run on scope exit to clean up the variable. Use of this construction and destruction mechanism is what is usually meant by RAII in C++.
In C, this programming error can easily happen.
typedef struct
{
int *data;
} Trivial_C;
void
my_c_function(void)
{
Trivial_C t;
t.data=malloc(5*sizeof(int));
... do something with t.data ...
} // oops! t does not exist anymore but the allocated
// memory that was known through t.data still exists!
In C++, RAII relies on destructors to do some cleanup
when an object disappears.
struct Trivial_Cpp
{
int *data;
Trivial_Cpp() : data{new int[5]} {} // data is allocated at creation
~Trivial_Cpp() { delete[] data; } // data is released at destruction
};
void
my_cpp_function()
{
Trivial_Cpp t;
... do something with t.data ...
} // OK, t does not exist anymore and the destructor has
// been called, so the allocated memory has been released
Of course these code snippets are trivial and largely incomplete.
Moreover, you rarely need to allocate memory by yourself; std::vector
for example will do it perfectly for you (because it uses RAII).
I always thought that C++ gets this behavior from C.
No, C++ and C are wildly different languages (by now) and differ in many aspects, often surprising.
First, you should understand different ways of lifetimes of objects (an object, in C speak, is a thing that uses memory, it hasn't got anything to do with Object Oriented Programming). In C there are three kinds of lifetimes:
static: Things that get allocated before the program start and destroyed afterwards. All global variables or static local variables. Static objects are implicitly initialized to 0/0.0 or NULL for pointer objects respectively.
dynamic: Objects that are created with the help of an allocation function such as malloc which in turn usually calls the OS via syscall (eg. sys_brk) to create space on the heap. This is an implementation detail though, C is very vague about how exactly the dynamic memory is acquired and has no notion of the heap.
When you don't need the memory anymore, you should free the object.
automatic: This is what happens when you simply create local variable without much thinking. The space is usually allocated on the stack and thus it will be invalid as soon as it leaves its scope.
const int GLOBAL_VARIABLE; // static lifetime
struct s {
int a;
}
void foo(void)
{
static int local_static_variable; // static lifetime as well.
int x; // automatic lifetime
struct s t; // automatic as well
struct s *p = malloc(sizeof (*p)); // while the pointer p itself is automatic, it points to an object of dynamic lifetime
{
int y; // automatic variable
}
// y out of scope: "freed"
free(p); // object pointed to by p must be freed.
} // x and p go out of scope
C++ with RAII introduces the usability of automatic freeing when something goes out of scope for more complex structures and objects allocated on the heap. For example you may have a structure that contains pointers objects which contain pointers to objects etc. In C, automatic allocation of the first-level structure only allocates memory for the pointers but not the objects within. Nor, if you allocate the memory for those objects using malloc, will it free them if the primary structure goes out of scope:
struct s {
int *array;
}
void foo(void)
{
struct s; // structure automatically allocated, but s.array is undefined
s.array = calloc(10, sizeof (*s.array)); // allocate space for 10 elements in array
s.array[0] = 0xf00;
free(s.array); // must free space acquired earlier
}
// s goes out of scope.
// if we hadn't free'd s.array, the allocated space would still "be there"
C++ allows you to define constructors and destructors for each object and subobject that will automatically allocate and free all subobjects, s.t. if s would go out of scope, s.array would be deallocated as well.
Related
This is my first question on stack overflow. Apologies if this is a "dumb" question, but I'm currently learning C++, and I'm a little confused by something. As I understand it, in the code below, the variable "myVariable" is declared on the heap but instantiated in the constructor on the stack. So where does it "live" - on the heap or the stack?
class MyClass{
int _myVariable;
MyClass(int i){
_myVariable = i;
}
}
The member variable is allocated according to how class is instantiated.
void example() {
MyClass a{17}; // This allocates memory on stack
MyClass *b = new MyClass(17); // This allocates memory on heap
}
"Stack" and "Heap" are implementation details. The C++ standard defines Automatic Storage and Dynamic Storage.
The most common implementations for the storage of variables are stack and heap, respectively.
The new operator makes an object live on the dynamic storage:
MyClass* mc = new MyClass(14);.
Note how we now need to use a pointer to access it.
With automatic storage, we can omit the pointer semantics:
MyClass mc = MyClass(14); // constructs an object on the automatic storage.
The object lifetime is managed - you've guessed - automatically. More precisely until the end of the scope.
With dynamically allocated objects, you have to manage the lifetime of the objects yourself.
There are cases where you can't use automatic storage: Namely polymorphism.
If MyClass is polymorphic (that means, it has virtual functions), you can't put it into the automatic storage since the compiler needs to know the size of an object. Since with polymorphism, the size of the pointed-to object can change at runtime it's not possible to create it on the automatic storage.
MyClass c = MyClass2(); //Object Slicing
c.foo(); // calls MyClass::foo()
MyClass* cc = new MyClass2(); //No Object Slicing
cc->foo(); // calls MyClass2::foo();
There are helper classes that take away the responsibility to clean up your memory:
unique_ptr and shared_ptr (although the latter is used rarely).
In the given code, nothing is allocated, you have a mere class declaration.
It is contradictory (and wrong) that "myVariable" is declared on the heap while instantiated in the constructor on the stack.
A simple constructor like yours does no allocation, it just assigns value upon creation of a class instance. Constructors do not allocate the instance, destructors do not deallocate it.
The allocation being done on the heap or on the stack will depend on how you use the class (as a plain variable or with a pointer).
It depends on where does the object live. If the actual object is on the heap the variable also lives on the heap. If the object lives on the stack the variable also lives on the stack.
Look at this example:
MyClass myObject = MyClass(5); // myObject lives on the stack and thus the variable i for myObject also lives on the stack
MyClass* newObject = new MyClass(5); // newObject is allocated on the heap and the variable i for newObject lives on the heap
delete newObject; // since newObject is created using new we must free the memory after use
What I understand from RAII is whenever you need to allocate memory manually with new etc. you need to free it too. So, instead of freeing it manually, you should create classes with constructor and destructor to do the job.
So, what are the following people talking about?
From: The meaning of the term - Resource Acquisition Is Initialization
The problem is that int * p = malloc(1000); is also initialization of an (integer) object, but it's not the kind of initialization we mean in the context of RAII.
...
#Fred: Indeed. int* is not a RAII type because it doesn't do cleanup. So it's not what RAII means, even though it is what RAII literally says.
Well, I know malloc is used in C, and new is used in C++.
Using malloc per se is not RAII because the resources are not freed when the variable goes out of scope, causing leaks of memory. You can make it RAII if you wrap this inside a class and free the resources in the destructor, because local class instances do die when they go out of scope. However, it should be noted what is being discussed here: the int * type is not RAII, and if you enclose it in a RAII type it still isn't. The wrapper doesn't make it RAII, so the RAII type here is the wrapper, not the pointer itself.
As requested in the comments: RAII stands for Resource Acquisition Is Initialisation and it's a design paradigm that combines the allocation of resources with the initialisation and destruction of objects. You don't seem far from understanding it: when an object is instantiated it allocates all the necessary resources (memory, file descriptors, streams, and so on) and frees them when it goes out of scope or the object is otherwise destructed. This is a common paradigm in C++ because C++ classes are RAII (that is, they die when they go out of scope) and as such it's easy to guarantee proper cleanup. The obvious upside being that you don't need to worry about manual cleanup and tracking variable lifetime.
On a related note, notice that this refers to stack allocation, not heap. What this means is that whatever the means you use for allocation (new/malloc vs delete/free) it still isn't RAII; memory that is allocated dynamically does not get magically freed, that's a given. When a variable is allocated on the stack (local variables) they are destroyed when the scope dies.
Example:
class MyObject
{
public:
MyObject()
{
// At this point resources are allocated (memory, files, and so on)
// In this case a simple allocation.
// malloc would have been just as fine
this->_ptr = new int;
}
~MyObject()
{
// When the object is destructed all resources are freed
delete this->_ptr;
}
private:
int * _ptr;
};
The previous sample code implements a RAII wrapper over a native pointer. Here's how to use it:
void f()
{
MyObject obj;
// Do stuff with obj, not including cleanup
}
In the previous example the int pointer is allocated when the variable is instantiated (at declaration time) and freed when the f call terminates, causing the variable to go out of scope and calling its destructor.
Note: As mentioned in the comments by Jarod42 the given example does not conform to the rule of 3 or the rule of 5, which are common thumb rules in C++. I would rather not add complexity to the given example, and as such I'll complete it here. These rules indicate that, if a method from a given set is implemented, then all methods of the set should be implemented, and those methods are the copy and move constructors, the assignment and move operators, and the destructor. Notice at first that this is a general rule, which means that is not mandatory. For instance, immutable objects should not implement assignment and move operators at all. In this case, if the object is to implement these operators it would probably imply reference counting, as multiple copies of the resource exist the destructor must not free the resources until all copies are destroyed. I believe that such an implementation would fall out of scope and as such I'm leaving it out.
By example
NOT RAII:
void foo()
{
int* p = malloc(sizeof(int) * N);
// do stuff
free(p);
}
also NOT RAII:
void foo()
{
int* p = new int[N];
// do stuff
delete[] p;
}
RAII:
struct MyResourceManager
{
int* p;
MyResourceManager(size_t n) : p(malloc(sizeof(int) * n)) { }
~MyResourceManager() { free(p); }
};
void foo()
{
MyResourceManager resource(N);
// doing stuff with resource.p
}
Also RAII (better):
struct MyResourceManager
{
int* p;
MyResourceManager(size_t n) : p(new int[n]) { }
~MyResourceManager() { delete[] p; }
};
void foo()
{
MyResourceManager resource(N);
// doing stuff with resource.p
}
Also RAII (best for this use case):
void foo()
{
std::unique_ptr<int[]> p(new int[N]);
// doing stuff with p
}
RAII is not use of operator new nor is it use of malloc().
It essentially means that, in the process of initialising an object, all resources that object needs to function are allocated. The counterpart requirement is that, in the process of destroying the object, that the resources it has allocated are released.
The concept applies to memory (most commonly), but also to any other resource that needs to be managed - file handles (opened in initialisation, closed when done), mutexes (grabbed in initialisation, released when done), communication ports, etc etc.
In C++, RAII is typically implemented by performing initialisation in constructors of an object, and the release of resources is done in the destructor. There are wrinkles such as other member functions possibly reallocating (e.g. resizing a dynamically allocated array) - in those cases, the member functions must ensure they do things in a way to ensure all resources allocated are appropriately released when the destructor is done. If there are multiple constructors, they need to do things consistently. You'll see this described as something like the constructor setting a class invariant (i.e. that resources are allocated correctly), member functions maintaining that invariant, and the destructor being able to clean up because the invariant is maintained.
The advantage of RAII - if done right - is that non-static variable lifetime is managed by the compiler (when an object goes out of scope, its destructor is invoked). So, the resources will be cleaned up correctly.
However, the requirement is always that the destructor does the cleanup (or that data members of the class have their own destructors that do the required cleanup). If constructor initialises an int * using malloc(), then it is not enough to assume the destructor will clean up - the destructor must pass that pointer to free(). If you don't do that, the C++ compiler will not magically find some way to release the memory for you (the pointer will no longer exist when the destructor is done, but the allocated memory it pointed to will not be released - so the result is a memory leak). C++ does not inherently use garbage collection (which is a trap for people used to garbage collected languages assuming that garbage collection will occur).
And it is undefined behaviour to use malloc() to allocate memory, and operator delete in any form to release it.
It is generally preferable to not use malloc() and free() in C++, because they do not work well with object construction and destruction (invoking constructors and destructors). Use operator new instead (and for whatever form of operator new you use, use the corresponding operator delete). Or, better yet, use standard C++ containers (std::vector, etc) as much as possible to avoid the need to worry about manually releasing memory you allocate.
Destruction of int* doesn't release the resources. It isn't safe to just let it go out of scope, so it isn't RAII.
The int * could be be a member of a class that deletes the int* in its destructor, which is essentially what unique_ptr of an int does. You make things like this RAII by wrapping them in code that encapsulates the deletion.
The discussion is about code that literally does initialization upon resource acquisition, but doesn't follow the RAII design.
In the shown example with malloc, 1000 bytes of memory are allocated (resource allocation) and a variable p (pointer to int) is initialized with the result (initialization). However, this is obviously not an example of RAII, because the object (of type int *) doesn't take care of the acquired resource in its destructor.
So no, malloc itself can not be RAII in some situations, it is an example of non-RAII code that nevertheless does "Initialization on Resource Acquisition" which might be confusing for new c++ programmers on first glance.
In C++, unique_ptr represents a pointer that "owns" the thing it points to. You can supply the release function as second argument:
std::unique_ptr<int[], std::function<void(void*)>>
p( (int *)malloc(1000 * sizeof(int)), std::free );
Of course, there's not much reason to do this instead of just using new (when the default deleter delete will do the right thing).
Yes, you can deal with int * p = malloc(1000); using the RAII paradigm. Smart pointers and std::vector use a very similar technique though they don't probably use malloc and prefer to use new instead.
Here's a very simplistic look at what one can do with malloc. MyPointer is far from being useful in a real application. Its only purpose is to demonstrate the principle of RAII.
class MyPointer
{
public:
MyPointer(size_t s) : p(malloc(s)) {}
~MyPionter() { free(p); }
int& operator[](size_t index) { return p[index]; }
private:
int* p;
};
int main()
{
// By initializing ptr you are acquiring resources.
// When ptr gets destructed, the resource is released.
MyPointer ptr(1000);
ptr[0] = 10;
std::cout << ptr[0] << std::endl;
}
The core idea behind RAII is:
Treat resource acquisition as though you are initializing an object.
Make sure the acquired resource(s) is(are) released when the object is destructed.
You can read more on RAII at Wikepedia.
So, what are the following people talking about?
What is RAII?
RAII in a nutshell is a very simple idea. It is the idea that no object may exist at all unless it is fully initialised.
Why is that good?
We now have a concrete guarantee that a 'half built' object cannot be accidentally used - because at no point in the logical flow of the program can it possibly exist.
How do we achieve it?
a) always manage resources (memory, files, mutex locks, database connections) in a class of their own which is specifically tailored to only managing that resource.
b) build complex logic out of collections of objects covered by [a]
c) Always throw if anything in the constructor fails (to guarantee that a failed object cannot exist)
d) if we are managing more than one resource in a class, we ensure that a failed construction cleans up the parts that have already been constructed (NOTE: this is hard [sometimes impossible], and why at this point you should be referred back to [a])
Sounds hard?
Initialising your objects completely in the initialiser list, while wrapping all external resources in a manager class (e.g. files, memory) achieves perfect RAII effortlessly.
What's the advantage?
Your program may now contain only logic which makes it easier to reason about and to read. The compiler will take care of all resource management perfectly.
Effortless Compound Resource Management
An example of RAII that's hard without manager classes and easy with them?
struct double_buffer
{
double_buffer()
: buffer1(std::nullptr) // NOTE: redundant zero construction
, buffer2(std::nullptr)
{
buffer1 = new char[100]; // new can throw!
try {
buffer2 = new char[100]; // if this throws we have to clean up buffer1
}
catch(...) {
delete buffer1; // clean up buffer1
throw; // rethrow because failed construction must throw!
}
}
// IMPORTANT!
// you MUST write or delete copy constructors, move constructor,
// plus also maybe move-assignment or move-constructor
// and you MUST write a destructor!
char* buffer1;
char* buffer2;
};
now the RAII version:
struct double_buffer
{
double_buffer()
: buffer1(new char[100]) // memory immediately transferred to manager
, buffer2(new char[100]) // if this throws, compiler will handle the
// correct cleanup of buffer1
{
// nothing to do here
}
// no need to write copy constructors, move constructor,
// move-assignment or move-constructor
// no need to write destructor
std::unique_ptr<char[]> buffer1;
std::unique_ptr<char[]> buffer2;
};
How does it improve my code?
some safe code that uses RAII:
auto t = merge(Something(), SomethingElse()); // pretty clear eh?
t.performAction();
the same code that does not use RAII:
TargetType t; // at this point uninitialised.
Something a;
if(a.construct()) {
SomethingElse b;
if (b.construct()) {
bool ok = merge_onto(t, a, b); // t maybe initialised here
b.destruct();
a.destruct();
if (!ok)
throw std::runtime_error("merge failed");
}
else {
a.destruct();
throw std::runtime_error("failed to create b");
}
}
else {
throw std::runtime_error("failed to create a");
}
// ... finally, we may now use t because we can (just about) prove that it's valid
t.performAction();
The difference
The RAII code is written solely in terms of logic.
The non-RAII code is 40% error handling and 40% lifetime management and only 20% logic. Furthermore, the logic is hidden in amongst all the other garbage, making even these 11 lines of code very hard to reason about.
I am trying to understand the difference between the stack and heap memory, and this question on SO as well as this explanation did a pretty good job explaining the basics.
In the second explanation however, I came across an example to which I have a specific question, the example is this:
It is explained that the object m is allocated on the heap, I am just wondering if this is the full story. According to my understanding, the object itself indeed is allocated on the heap as the new keyword has been used for its instantiation.
However, isn't it that the pointer to object m is on the same time allocated on the stack? Otherwise, how would the object itself, which of course is sitting in the heap be accessed. I feel like for the sake of completeness, this should have been mentioned in this tutorial, leaving it out causes a bit of confusion to me, so I hope someone can clear this up and tell me that I am right with my understanding that this example should have basically two statements that would have to say:
1. a pointer to object m has been allocated on the stack
2. the object m itself (so the data that it carries, as well as access to its methods) has been allocated on the heap
Your understanding may be correct, but the statements are wrong:
A pointer to object m has been allocated on the stack.
m is the pointer. It is on the stack. Perhaps you meant pointer to a Member object.
The object m itself (the data that it carries, as well as access to its methods) has been allocated on the heap.
Correct would be to say the object pointed by m is created on the heap
In general, any function/method local object and function parameters are created on the stack. Since m is a function local object, it is on the stack, but the object pointed to by m is on the heap.
"stack" and "heap" are general programming jargon. In particular , no storage is required to be managed internally via a stack or a heap data structure.
C++ has the following storage classes
static
automatic
dynamic
thread
Roughly, dynamic corresponds to "heap", and automatic corresponds to "stack".
Moving onto your question: a pointer can be created in any of these four storage classes; and objects being pointed to can also be in any of these storage classes. Some examples:
void func()
{
int *p = new int; // automatic pointer to dynamic object
int q; // automatic object
int *r = &q; // automatic pointer to automatic object
static int *s = p; // static pointer to dynamic object
static int *s = r; // static pointer to automatic object (bad idea)
thread_local int **t = &s; // thread pointer to static object
}
Named variables declared with no specifier are automatic if within a function, or static otherwise.
When you declare a variable in a function, it always goes on the stack. So your variable Member* m is created on the stack. Note that by itself, m is just a pointer; it doesn't point to anything. You can use it to point to an object on either the stack or heap, or to nothing at all.
Declaring a variable in a class or struct is different -- those go where ever the class or struct is instantiated.
To create something on the heap, you use new or std::malloc (or their variants). In your example, you create an object on the heap using new and assign its address to m. Objects on the heap need to be released to avoid memory leaks. If allocated using new, you need to use delete; if allocated using std::malloc, you need to use std::free. The better approach is usually to use a "smart pointer", which is an object that holds a pointer and has a destructor that releases it.
Yes, the pointer is allocated on the stack but the object that pointer points to is allocated on the heap. You're correct.
However, isn't it that the pointer to object m is on the same time
allocated on the stack?
I suppose you meant the Member object. The pointer is allocated on the stack and will last there for the entire duration of the function (or its scope). After that, the code might still work:
#include <iostream>
using namespace std;
struct Object {
int somedata;
};
Object** globalPtrToPtr; // This is into another area called
// "data segment", could be heap or stack
void function() {
Object* pointerOnTheStack = new Object;
globalPtrToPtr = &pointerOnTheStack;
cout << "*globalPtrToPtr = " << *globalPtrToPtr << endl;
} // pointerOnTheStack is NO LONGER valid after the function exits
int main() {
// This can give an access violation,
// a different value after the pointer destruction
// or even the same value as before, randomly - Undefined Behavior
cout << "*globalPtrToPtr = " << *globalPtrToPtr << endl;
return 0;
}
http://ideone.com/BwUVgm
The above code stores the address of a pointer residing on the stack (and leaks memory too because it doesn't free Object's allocated memory with delete).
Since after exiting the function the pointer is "destroyed" (i.e. its memory can be used for whatever pleases the program), you can no longer safely access it.
The above program can either: run properly, crash or give you a different result. Accessing freed or deallocated memory is called undefined behavior.
I am still new to C++. I have found that you can instantiate an instance in C++ with two different ways:
// First way
Foo foo;
foo.do_something();
// Second way
Baz *baz = new Baz();
baz->do_something();
And with both I don't see big difference and can access the attributes. Which is the preferred way in C++? Or if the question is not relevant, when do we use which and what is the difference between the two?
Thank you for your help.
The question is not relevant: there's no preferred way, those just do different things.
C++ both has value and reference semantics. When a function asks for a value, it means you'll pass it a copy of your whole object. When it asks for a reference (or a pointer), you'll only pass it the memory address of that object. Both semantics are convertible, that is, if you get a value, you can get a reference or a pointer to it and then use it, and when you get a reference you can get its value and use it. Take this example:
void foo(int bar) { bar = 4; }
void foo(int* bar) { *bar = 4; }
void test()
{
int someNumber = 3;
foo(someNumber); // calls foo(int)
std::cout << someNumber << std::endl;
// printed 3: someNumber was not modified because of value semantics,
// as we passed a copy of someNumber to foo, changes were not repercuted
// to our local version
foo(&someNumber); // calls foo(int*)
std::cout << someNumber << std::endl;
// printed 4: someNumber was modified, because passing a pointer lets people
// change the pointed value
}
It is a very, very common thing to create a reference to a value (i.e. get the pointer of a value), because references are very useful, especially for complex types, where passing a reference notably avoids a possibly costly copy operation.
Now, the instantiation way you'll use depends on what you want to achieve. The first way you've shown uses automatic storage; the second uses the heap.
The main difference is that objects on automatic storage are destroyed with the scope in which they existed (a scope being roughly defined as a pair of matching curly braces). This means that you must not ever return a reference to an object allocated on automatic storage from a regular function, because by the time your function returns, the object will have been destroyed and its memory space may be reused for anything at any later point by your program. (There are also performance benefits for objects allocated on automatic storage because your OS doesn't have to look up a place where it might put your new object.)
Objects on the heap, on the other hand, continue to exist until they are explicitly deleted by a delete statement. There is an OS- and platform-dependant performance overhead to this, since your OS needs to look up your program's memory to find a large enough unoccupied place to create your object at. Since C++ is not garbage-collected, you must instruct your program when it is the time to delete an object on the heap. Failure to do so leads to leaks: objects on the heap that are no longer referenced by any variable, but were not explicitly deleted and therefore will exist until your program exits.
So it's a matter of tradeoff. Either you accept that your values can't outlive your functions, or you accept that you must explicitly delete it yourself at some point. Other than that, both ways of allocating objects are valid and work as expected.
For further reference, automatic storage means that the object is allocated wherever its parent scope was. For instance, if you have a class Foo that contains a std::string, the std::string will exist wherever you allocate your Foo object.
class Foo
{
public:
// in this context, automatic storage refers to wherever Foo will be allocated
std::string a;
};
int foo()
{
// in this context, automatic storage refers to your program's stack
Foo bar; // 'bar' is on the stack, so 'a' is on the stack
Foo* baz = new Foo; // 'baz' is on the heap, so 'a' is on the heap too
// but still, in both cases 'a' will be deleted once the holding object
// is destroyed
}
As stated above, you cannot directly leak objects that reside on automatic storage, but you cannot use them once the scope in which they were created is destroyed. For instance:
int* foo()
{
int a; // cannot be leaked: automatically managed by the function scope
return &a; // BAD: a doesn't exist anymore
}
int* foo()
{
int* a = new int; // can be leaked
return a; // NOT AS BAD: now the pointer points to somewhere valid,
// but you eventually need to call `delete a` to release the memory
}
The first way -- "allocating on the stack" -- is generally faster and preferred much of the time. The constructed object is destroyed when the function returns. This is both a blessing -- no memory leaks! -- and a curse, because you can't create an object that lives for a longer time.
The second way -- "allocating on the heap" is slower, and you have to manually delete the objects at some point. But it has the advantage that the objects can live on until you delete them.
The first way allocates the object on the stack (though the class itself may have heap-allocated members). The second way allocates the object on the heap, and must be explicitly delete'd later.
It's not like in languages like Java or C# where objects are always heap-allocated.
They do very different things. The first one allocates an object on the stack, the 2nd on the heap. The stack allocation only lasts for the lifetime of the declaring method; the heap allocation lasts until you delete the object.
The second way is the only way to dynamically allocate objects, but comes with the added complexity that you must remember to return that memory to the operating system (via delete/delete[]) when you are done with it.
The first way will create the object on the stack, and the object will go away when you return from the function it was created in.
The second way will create the object on the heap, and the object will stick around until you call delete foo;.
If the object is just a temporary variable, the first way is better. If it's more permanent data, the second way is better - just remember to call delete when you're finally done with it so you don't build up cruft on your heap.
Hope this helps!
In my browsings amongst the Internet, I came across this post, which includes this
"(Well written) C++ goes to great
lengths to make stack automatic
objects work "just like" primitives,
as reflected in Stroustrup's advice to
"do as the ints do". This requires a
much greater adherence to the
principles of Object Oriented
development: your class isn't right
until it "works like" an int,
following the "Rule of Three" that
guarantees it can (just like an int)
be created, copied, and correctly
destroyed as a stack automatic."
I've done a little C, and C++ code, but just in passing, never anything serious, but I'm just curious, what it means exactly?
Can someone give an example?
Stack objects are handled automatically by the compiler.
When the scope is left, it is deleted.
{
obj a;
} // a is destroyed here
When you do the same with a 'newed' object you get a memory leak :
{
obj* b = new obj;
}
b is not destroyed, so we lost the ability to reclaim the memory b owns. And maybe worse, the object cannot clean itself up.
In C the following is common :
{
FILE* pF = fopen( ... );
// ... do sth with pF
fclose( pF );
}
In C++ we write this :
{
std::fstream f( ... );
// do sth with f
} // here f gets auto magically destroyed and the destructor frees the file
When we forget to call fclose in the C sample the file is not closed and may not be used by other programs. (e.g. it cannot be deleted).
Another example, demonstrating the object string, which can be constructed, assigned to and which is destroyed on exiting the scope.
{
string v( "bob" );
string k;
v = k
// v now contains "bob"
} // v + k are destroyed here, and any memory used by v + k is freed
In addition to the other answers:
The C++ language actually has the auto keyword to explicitly declare the storage class of an object. Of course, it's completely needless because this is the implied storage class for local variables and cannot be used anywhere. The opposite of auto is static (both locally and globall).
The following two declarations are equivalent:
int main() {
int a;
auto int b;
}
Because the keyword is utterly useless, it will actually be recycled in the next C++ standard (“C++0x”) and gets a new meaning, namely, it lets the compiler infer the variable type from its initialization (like var in C#):
auto a = std::max(1.0, 4.0); // `a` now has type double.
Variables in C++ can either be declared on the stack or the heap. When you declare a variable in C++, it automatically goes onto the stack, unless you explicitly use the new operator (it goes onto the heap).
MyObject x = MyObject(params); // onto the stack
MyObject * y = new MyObject(params); // onto the heap
This makes a big difference in the way the memory is managed. When a variable is declared on the stack, it will be deallocated when it goes out of scope. A variable on the heap will not be destroyed until delete is explicitly called on the object.
Stack automatic are variables which are allocated on the stack of the current method. The idea behind designing a class which can acts as Stack automatic is that it should be possible to fully initialize it with one call and destroy it with another. It is essential that the destructor frees all resources allocated by the object and its constructor returns an object which has been fully initialized and ready for use. Similarly for the copy operation - the class should be able to be easily made copies, which are fully functional and independent.
The usage of such class should be similar to how primitive int, float, etc. are used. You define them (eventually give them some initial value) and then pass them around and in the end leave the compiler to the cleaning.
Correct me if i'm wrong, but i think that copy operation is not mandatory to take full advantage of automatic stack cleaning.
For example consider a classic MutexGuard object, it doesn't need a copy operation to be useful as stack automatic, or does it ?