• Advertisement
Sign in to follow this  

I think I don't understand dynamic memory

This topic is 1081 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

hello people,

 

Currently i'm learning C++. My book explains Dynamic Memory a bit like this:

-You have to now the "value" of a static array when you write the program. But with a dynamic array you can do this in run time.

Dynamic Memory is basically a pointer in a class. This pointer will be pointing to a block of memory (array). You have to write a destructor for this, like this:

class IntArray{
private:
      int amountOfValuesInArray;
      int *p;
public:
     IntArray(amount)
           :amountOfValuesInArray(amount){
                 p = new int [amountOfValuesInArray]
           }

ETC. 

But then I get to smart pointers: Smart pointers don't need a destructor, but will "free" the memory by themselves, and then I get the following example (I copied it and it isn't in english, I hope it's understandable, otherwise I will translate it(tell me it)):

class Student {
private:
  string naam, opleiding, geslacht;
  int nummer;

public:
  Student( string n, string opl, string gesl, int nr )
    : naam(n), opleiding(opl), geslacht(gesl), nummer(nr) {
  }

 string toString() const {
    ostringstream os;
    os << naam << ", " << opleiding << ", " << geslacht;
    os << ", " << nummer << endl;
    return os.str();
  }
};

int main() {
  //shared_ptr<Student> sp( new Student( "Gertjan", "wiskunde", "m", 313 ) );
  auto sp = make_shared<Student>( "Gertjan", "wiskunde", "m", 313 );
  cout << sp -> toString() << endl;
  cin.get();

}

 

And the book says that at the end nothing is pointing towards the memory of sp anymore, so the memory will be "released".

But in this class there isn't any dynamic memory (array/pointer) right, so I think I don't understand it. Could you tell me what I understand wrong and how it works then?

 

Thanks

 

Share this post


Link to post
Share on other sites
Advertisement

Oh, then I don't understand Dynamic Memory, could someone please explain it to me, or point me to an article or something like that, because I dind't understand Rip-Off's explaination completely. 

Share this post


Link to post
Share on other sites

I dind't understand Rip-Off's explaination completely. 

 

 

 


the explicit memory management is done by the implicitly called destructors. So the std::make_shared<> will dynamically allocate the object, and the destructor deallocates it.

 

When any object goes out of scope, its destructor is called. When the main function is exited, sp goes out of scope, so its destructor is called. That shared_ptr destructor ends up deallocating the memory it allocated when it was constructed. Just like your IntArray class allocated in its constructor, and deallocated in the destructor (I'm assuming so, you didn't post your destructor code).

 

So if you had the code:

int main() {
    IntArray blah(10);
    // etc... do some more stuff
}

When the main function exits, IntArray goes out of scope and its destructor will be called, thus freeing the *p it allocated in its constructor.

Edited by phil_t

Share this post


Link to post
Share on other sites

 


I dind't understand Rip-Off's explaination completely. 

 

 

 


the explicit memory management is done by the implicitly called destructors. So the std::make_shared<> will dynamically allocate the object, and the destructor deallocates it.

 

When any object goes out of scope, its destructor is called. When the main function is exited, sp goes out of scope, so its destructor is called. That shared_ptr destructor ends up deallocating the memory it allocated when it was constructed. Just like your IntArray class allocated in its constructor, and deallocated in the destructor (I'm assuming so, you didn't post your destructor code).

 

So if you had the code:

int main() {
    IntArray blah(10);
    // etc... do some more stuff
}

When the main function exits, IntArray goes out of scope and its destructor will be called, thus freeing the *p it allocated in its constructor.

 

 

I understand that, but I meant just the whole thing Dynamic Memory in general. (The theory behind it)

Edited by Dalphin

Share this post


Link to post
Share on other sites

Lets say you were making a program to store students quiz grades for the semester.

You chose to store it in a dynamic array of ints.
Now being in different classes the students aren't going to have the exact same number of quiz scores.

so when you got to the point where you needed to type in the variable, without a dynamically allocated array it would be like:

 

int studentGrade[5];

 

You would have to hardcore that number in there. Which in this case you would be making an assumption as to how many quiz's he has taken. What if he took more than 5? What if he took less? Making a dynamically allocated array you can put a variable in those brackets so that way the user can specify at run time how many he's going to enter. So you could use a variable like this instead as opposed to that hardcoded number/#defines and whatnot.

studentGrade[numOfGrades]

 

So prior you can prompt the user asking them how many grades will they be entering, or however you want to implement that part.

If I misunderstood what you were asking for sorry.

Edited by Delite413

Share this post


Link to post
Share on other sites

Lets say you were making a program to store students quiz grades for the semester.

You chose to store it in a dynamic array of ints.
Now being in different classes the students aren't going to have the exact same number of quiz scores.

so when you got to the point where you needed to type in the variable, without a dynamically allocated array it would be like:

 

int studentGrade[5];

 

You would have to hardcore that number in there. Which in this case you would be making an assumption as to how many quiz's he has taken. What if he took more than 5? What if he took less? Making a dynamically allocated array you can put a variable in those brackets so that way the user can specify at run time how many he's going to enter. So you could use a variable like this instead as opposed to that hardcoded number/#defines and whatnot.

studentGrade[numOfGrades];

 

So prior you can prompt the user asking them how many grades will they be entering, or however you want to implement that part.

If I misunderstood what you were asking for sorry.

Really thanks for your effort, but I understood that already.

 

I Understand the array part, but in my example, there is no array, so I don't understand it properly there.

 

Thanks again!!!!!

Share this post


Link to post
Share on other sites

 

Lets say you were making a program to store students quiz grades for the semester.

You chose to store it in a dynamic array of ints.
Now being in different classes the students aren't going to have the exact same number of quiz scores.

so when you got to the point where you needed to type in the variable, without a dynamically allocated array it would be like:

 

int studentGrade[5];

 

You would have to hardcore that number in there. Which in this case you would be making an assumption as to how many quiz's he has taken. What if he took more than 5? What if he took less? Making a dynamically allocated array you can put a variable in those brackets so that way the user can specify at run time how many he's going to enter. So you could use a variable like this instead as opposed to that hardcoded number/#defines and whatnot.

studentGrade[numOfGrades];

 

So prior you can prompt the user asking them how many grades will they be entering, or however you want to implement that part.

If I misunderstood what you were asking for sorry.

Really thanks for your effort, but I understood that already.

 

I Understand the array part, but in my example, there is no array, so I don't understand it properly there.

 

Thanks again!!!!!

 

 

To my knowledge it didn't make an array in the second one. It dynamically created an instance of student.

That line with the make_shared ( like I said I haven't used smart pointers, but this is an assumption ), that line is the equivalent of doing it manually say:

 

_student = new Student("whatever arguments they used");

 

and if you wanted to delete it manually you would've done:

delete _student;

_student = nullptr;

 

but since it was a smart pointer you didn't have to worry about doing the above.

Share this post


Link to post
Share on other sites

 

 

Lets say you were making a program to store students quiz grades for the semester.

You chose to store it in a dynamic array of ints.
Now being in different classes the students aren't going to have the exact same number of quiz scores.

so when you got to the point where you needed to type in the variable, without a dynamically allocated array it would be like:

 

int studentGrade[5];

 

You would have to hardcore that number in there. Which in this case you would be making an assumption as to how many quiz's he has taken. What if he took more than 5? What if he took less? Making a dynamically allocated array you can put a variable in those brackets so that way the user can specify at run time how many he's going to enter. So you could use a variable like this instead as opposed to that hardcoded number/#defines and whatnot.

studentGrade[numOfGrades];

 

So prior you can prompt the user asking them how many grades will they be entering, or however you want to implement that part.

If I misunderstood what you were asking for sorry.

Really thanks for your effort, but I understood that already.

 

I Understand the array part, but in my example, there is no array, so I don't understand it properly there.

 

Thanks again!!!!!

 

 

To my knowledge it didn't make an array in the second one. It dynamically created an instance of student.

That line with the make_shared ( like I said I haven't used smart pointers, but this is an assumption ), that line is the equivalent of doing it manually say:

 

_student = new Student("whatever arguments they used");

 

and if you wanted to delete it manually you would've done:

delete _student;

_student = nullptr;

 

but since it was a smart pointer you didn't have to worry about doing the above.

 

yes, but I don't understand exactly what's Dynamic about the _student = new Student("whatever arguments they used"); part

Share this post


Link to post
Share on other sites

yes, but I don't understand exactly what's Dynamic about the _student = new Student("whatever arguments they used"); part

 

You're using runtime logic to allocate space for a Student. ie. at runtime you're controlling the allocation and deallocation of the Student objects and the memory associated with them. You can create and delete as many or as few as you want.

 

If you need control of the number of them you create, or when they are created and destroyed, then you need to use "dynamic memory".

 

Another time you need dynamic memory is if you want to create an object and have its lifetime exist outside of the function it was created in. A function can return a pointer to a dynamically allocated object (which is very different than just returning a copy of the object).

Edited by phil_t

Share this post


Link to post
Share on other sites
I don't know if this constitutes a "theory", but maybe a good way to answer your qusetion is to illustrate some common scenarios, with examples, where a programmer might reach for dynamic memory allocation.

The programmer cannot predict the number of objects to run computations at compile time. Knowing the exact number of objects in advance is rare, in fact. There are two primary exceptions:
  • The domain itself has hard limits in place. For example, Chess is played on an 8 x 8 board with 16 pieces per player, so a program for playing chess can avoid dynamic allocation for storing the state of the board. However, the number of moves during the game is not known in advance, so dynamic memory would be required to provide a full game log.
  • The designer chooses an arbitrary limitation on some aspect of the program. This can be for a number of reasons, including not wanting to design a flexible UI that can cope with arbitrary amounts of data (thus avoiding complex workflows like search, sort and paging) or to achieve soft real time performance goals( in a game context this could be trying to ensure that no frame takes more than 16.6 milliseconds).
Another reason is that the lifetime of an object is unknown at compile time. It will almost certainly outlast the function that creates it, it may even outlast the object or objects it is first stored in. An example might be a particular map texture in a multi-player FPS client. Provided the server's map rotation continues to require that texture, it would be preferable to avoid unloading and reloading it. However, once the texture is no longer required, it can be remove to make way for the new textures the next map needs instead. Thus any given texture might be stored for the duration of one map, or several.

Another is the behaviour of the object cannot be precisely determined at compile time. Most object oriented languages implement polymorphism by allocating a dynamic amount of memory, and returning some kind of reference to this memory. Other parts of the code might take a more generic reference, e.g. a pointer to a super class in C++, and without knowing the exact size or layout of the object it can be made use of. Some simple games can be implemented such that every game object inherits from a very simple base class with a virtual function for updating itself (e.g. Asteroids). Most people find that this approach typically doesn't scale well once the number of object types starts to grow.

Finally, a programmer may be forced to use dynamic memory because the language or library they are using make use of it. In particular, it is common in C APIs not to expose the definition of a data structure, which provides maximum freedom for the library implementor when making changes. For example, the Simple Directmedia Library (SDL) is a C API which does this. Some of the API calls wouldn't necessarily require dynamic amounts of memory, but by hiding the details the library implementation can change the size of it's data structures without changing the public API. It also makes the API consistent, as now there is a common pattern for interacting with all parts of the API.

Share this post


Link to post
Share on other sites

Maybe I can try using analogy to explain it.

 

automatic allocation:

Imagine there is a restaurant with many tables and seats. You and your family go in the restaurant. The mute receptionist sees that you have 5 people, and leads you to a table G, with 5 seats. Now table G is occupied by your family. When you are done eating, you leave the restaurant. The receptionist sees that and table G is unoccupied. The next family of 5 that comes are able to use table G. This whole time, you did not speak to the receptionist at all, because he is mute.

 

dynamic allocation:

Now Imagine there is another restaurant with many tables and seats. You and your family go in the restaurant. The blind receptionist asks "how many people"? and you tell him 5. The blind receptionist finds an unoccupied table E with enough seats for 5 people. He's blind so he doesn't want to talk and trip, so he tells you where the table is. Now table E is occupied by your family. When you are done eating, you leave the restaurant. However, you forgot to tell the blind receptionist that you left. He still thinks table E is occupied by you, so table E will not be given to any customers.

 

tables and seats = memory, since they are space.

customers = data, since they are the contents that occupy space.

the act of entering/leaving restaurant = entering and leaving a scope.

the act of being led to a table by the mute receptionist = automatic allocation.

the act of telling the blind receptionist how many seats you need at the minimum, and getting the location of the seats/tables = dynamic allocation.

 

This analogy omits some details, but I hope that helps.

Share this post


Link to post
Share on other sites

yes, but I don't understand exactly what's Dynamic about the _student = new Student("whatever arguments they used"); part

The value stored in the pointer returned by Windows (or the Linux kernel)
That number is the address of the RAM cell where the block you just allocated starts.

Share this post


Link to post
Share on other sites

From the abstract side, the need for variable numbers of objects, variable array sizes, flexible object lifetimes and other uses of dynamic memory should be clear, but there are significant technical differences between different kinds of memory allocation (static, stack, heap).

Operators new and delete, called either directly or behind closed doors in smart pointer classes, interact with the operating system by requesting and releasing memory, which becomes part of the C++ heap; it's the only way to avoid arbitrary process memory limits (particularly stack size), avoid wasting memory by conservatively allocating more static data than needed, and thus have the program run out of memory only if the operating system fails to provide the minimum actually needed amount.

Share this post


Link to post
Share on other sites


Dynamic memory means that the memory lifetime isn't managed automatically by the language - like how when you call a function, memory is automatically provided for the various local variables you need.

 

I think one reason the OP is confused is that this is a confusing explanation. I'd consider things like std::vector to be part of the C++ language (it is part of the standard, even though it is implemented within the language) and it certainly feels more like automatically managed memory than not. In memory-managed languages, such as Java, there is still dynamic memory. Anyway, your second post is much clearer.

 

In the example provided, the Student object is somewhat of a red-herring. It is using a shared_ptr, which is a tool for handling dynamic memory, but that was an arbitrary choice. It's hard to understand what that shared_ptr is doing there and what it might provide in functionality. It is also being initialized with hard-coded strings, so everything is theoretically known at run-time. A compiler that is super aggressive and awesome at optimizing could replace the program with something that just outputs the correct line.

 

However, if you imagine a simple change to fill the Student object with information from the console, I think it's more clear what dynamic memory does. The strings within can be of arbitrary size. The memory for them is dynamic regardless of the Student object itself, and they are all automatically freed when the Student goes out of scope. The only limits on those strings are the pointer size, the OS, memory available, etc. - nothing hard-coded into the class. Internally, there must be three arrays for the strings that are allocated dynamically.

 

On top of that, if you know something about how those objects from the library work, you know there's an array of bytes storing the Student and the reference counter for the shared_ptr, there is a buffer within the ostringstream for building the string, and cin and cout almost certainly use some dynamic memory for handling input and output.

 

One last note:

 


The value stored in the pointer returned by Windows (or the Linux kernel)
That number is the address of the RAM cell where the block you just allocated starts.

 

You're not always getting memory straight from the OS with every "new" call you make. The implementation of the C++ memory manager handles allocating memory within your program, though it may have to allocate memory from the OS if it needs more, and there could be other system calls for making things thread safe, but individual allocations are, in general, the responsibility of the application. How or when it needs a system call to help is up to the memory manager.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement