Reputation: 342
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.
Upvotes: 1
Views: 336
Reputation: 811
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
local variables. Static objects are implicitly initialized to 0
/0.0
or NULL
for pointer objects respectively.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.free
the object.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.
Upvotes: 0
Reputation: 16825
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).
Upvotes: 2
Reputation: 1009
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++.
Upvotes: 2
Reputation: 238331
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.
Upvotes: 3