10.6 — Container classes

In real life, we use containers all the time. Your breakfast cereal comes in a box, the pages in your book come inside a cover and binding, and you might store any number of items in containers in your garage. Without containers, it would be extremely inconvenient to work with many of these objects. Imagine trying to read a book that didn’t have any sort of binding, or eat cereal that didn’t come in a box without using a bowl. It would be a mess. The value the container provides is largely in its ability to help organize and store items that are put inside it.

Similarly, a container class is a class designed to hold and organize multiple instances of another type (either another class, or a fundamental type). There are many different kinds of container classes, each of which has various advantages, disadvantages, and restrictions in their use. By far the most commonly used container in programming is the array, which you have already seen many examples of. Although C++ has built-in array functionality, programmers will often use an array container class (std::array or std::vector) instead because of the additional benefits they provide. Unlike built-in arrays, array container classes generally provide dynamic resizing (when elements are added or removed), remember their size when they are passed to functions, and do bounds-checking. This not only makes array container classes more convenient than normal arrays, but safer too.

Container classes typically implement a fairly standardized minimal set of functionality. Most well-defined containers will include functions that:

  • Create an empty container (via a constructor)
  • Insert a new object into the container
  • Remove an object from the container
  • Report the number of objects currently in the container
  • Empty the container of all objects
  • Provide access to the stored objects
  • Sort the elements (optional)

Sometimes certain container classes will omit some of this functionality. For example, arrays container classes often omit the insert and remove functions because they are slow and the class designer does not want to encourage their use.

Container classes implement a member-of relationship. For example, elements of an array are members-of (belong to) the array. Note that we’re using “member-of” in the conventional sense, not the C++ class member sense.

Types of containers

Container classes generally come in two different varieties. Value containers are compositions that store copies of the objects that they are holding (and thus are responsible for creating and destroying those copies). Reference containers are aggregations that store pointers or references to other objects (and thus are not responsible for creation or destruction of those objects).

Unlike in real life, where containers can hold whatever types of objects you put in them, in C++, containers typically only hold one type of data. For example, if you have an array of integers, it will only hold integers. Unlike some other languages, many C++ containers do not allow you to arbitrarily mix types. If you need containers to hold integers and doubles, you will generally have to write two separate containers to do this (or use templates, which is an advanced C++ feature). Despite the restrictions on their use, containers are immensely useful, and they make programming easier, safer, and faster.

An array container class

In this example, we are going to write an integer array class from scratch that implements most of the common functionality that containers should have. This array class is going to be a value container, which will hold copies of the elements it’s organizing. As the name suggests, the container will hold an array of integers, similar to std::vector<int>.

First, let’s create the IntArray.h file:

Our IntArray is going to need to keep track of two values: the data itself, and the size of the array. Because we want our array to be able to change in size, we’ll have to do some dynamic allocation, which means we’ll have to use a pointer to store the data.

Now we need to add some constructors that will allow us to create IntArrays. We are going to add two constructors: one that constructs an empty array, and one that will allow us to construct an array of a predetermined size.

We’ll also need some functions to help us clean up IntArrays. First, we’ll write a destructor, which simply deallocates any dynamically allocated data. Second, we’ll write a function called erase(), which will erase the array and set the length to 0.

Now let’s overload the [] operator so we can access the elements of the array. We should bounds check the index to make sure it’s valid, which is best done using the assert() function. We’ll also add an access function to return the length of the array. Here’s everything so far:

At this point, we already have an IntArray class that we can use. We can allocate IntArrays of a given size, and we can use the [] operator to retrieve or change the value of the elements.

However, there are still a few thing we can’t do with our IntArray. We still can’t change its size, still can’t insert or delete elements, and we still can’t sort it.

First, let’s write some code that will allow us to resize an array. We are going to write two different functions to do this. The first function, Reallocate(), will destroy any existing elements in the array when it is resized, but it will be fast. The second function, Resize(), will keep any existing elements in the array when it is resized, but it will be slow.

Whew! That was a little tricky!

Many array container classes would stop here. However, just in case you want to see how insert and delete functionality would be implemented we’ll go ahead and write those too. Both of these algorithms are very similar to resize().

Here is our IntArray container class in its entirety.


Now, let’s test it just to prove it works:

This produces the result:

40 1 2 3 5 20 6 7 8 30

Although writing container classes can be pretty complex, the good news is that you only have to write them once. Once the container class is working, you can use and reuse it as often as you like without any additional programming effort required.

It is also worth explicitly mentioning that even though our sample IntArray container class holds a built-in data type (int), we could have just as easily used a user-defined type (e.g. a Point class).

One more thing: If a class in the standard library meets your needs, use that instead of creating your own. For example, instead of using IntArray, you’re better off using std::vector<int>. It’s battle tested, efficient, and plays nicely with the other classes in the standard library. But sometimes you need a specialized container class that doesn’t exist in the standard library, so it’s good to know how to create your own when you need to. We’ll talk more about containers in the standard library once we’ve covered a few more fundamental topics.

10.7 -- std::initializer_list
10.5 -- Dependencies

170 comments to 10.6 — Container classes

  • Amir

    Thank you for showing this clearly .Was really great to get a deep look how std::vecotr working behind seen .

  • giang

    In the Resize() function above, is it necessary to 'delete [] m_data;' because right after that, we do 'm_data=data;', which we assign m_data with another/ new address (which is data's address)??

    • nascardriver

      After you override `m_data` with `data`, you've lost the old pointer and can no longer delete the memory it's pointing to. You'd be leaking memory.

      • giang

        Okay. Then if we were done the 'm_data=data;', do we need to 'delete [] data' too so that there won't be leaking memory??

        • nascardriver

          After `m_data = data`, `m_data` is equal to `data`, so `data` can go out of scope without a problem, because we copied it. `m_data` is then deleted later.

  • nerbet

    i was wondering if you could elaborate on line 13 in the IntArray example:

    i could'nt find much documentaion about that use of default keyword

    • nascardriver


      This is part of lesson 8.5's section "An implicitly generated default constructor". We defined a custom constructor `IntArray(int)`, so the compiler wouldn't normally generate a default constructor. Using `IntArray() = default` tells the compiler to generate a default constructor anyway.

  • kavin

    Hi, sorry but i have this doubt for quite sometime. Forgot to ask you before itself. Under IntArray.h, line 16,

    is using curly brackets , the same as using () for initializing m_length with length ?,

    So far, in some examples you have used {}, but for some u ve used () . I thought it was just a matter of preference. Is it ? or there is a reason behind it ?
    I referred chapter 8.5a and the rule is given as ,
    Rule: Favor uniform initialization over direct initialization if your compiler is C++11 compatible

    • nascardriver

      Brace initialization should be favored whenever possible. See lesson 1.4.
      Brace initialization {} is a form of direct initialization (), but more restrictive about conversions and more versatile.

  • David

    I have a question concered about the overloading operator[].when I insert the program into the line38-line42,the compiler can't compile it.But in the lesson 9-8,you say "we can define a non-const and a const version of operator[] separately."
    Thanks for replying

    • nascardriver

      There's no way to differentiate your 2 `operator[]` functions. You need to mark your second `operator[]` as `const` so that the compiler knows to use it for `const` objects, and the other one for non-`const` objects.

    • Al

      The only difference between your two ``operator[]`` overloads is their return type, which is NOT taken into account when assessing if two functions are different. In the present context, the (non-)constness of a function has nothing to do with its return value, but with the way the function manipulates its parameters: does it only access them (so it can be considered const) or does it also modifies them (so it can't be considered const)?

      The ``const`` keyword must be appended AFTER the parameter list and before the body of the function, as shown by nascardriver, in order to declare a member function as "a const function".

  • P


    Just a suggestion: Maybe you should explain the purpose of the IntArray class up front a bit better? It's not clear (at least to me personally), which makes it hard to follow along with the explanation. Are we trying to build a container that acts as an array of arrays? Or is it supposed to hold a number of unrelated arrays? Took me a while to figure out.  

    Thank you so much for all your hard work, it's been super helpful.

    • nascardriver

      I added a sentence to the beginning stating that `IntArray` is similar to `std::vector`. Does that clear things up?

      • P


        Yes, thank you, it's clear now!

        I just thought some newbies like me with no previous knowledge of containers might assume that an array is a container already. And if you're writing a container class, it would contain, well, a bunch of arrays as opposed to a single array with a std::vector-like implementation.

  • Anastasia

    great lesson! Containers seem like a very important and interesting thing in C++. I liked the implementation of IntArray, especially letting the user to choose whether they want to copy existing elements or not when resizing the array.

    But there's one point which worries me. The overloaded operator[] returns a reference to uninitialized memory... Isn't it UB or I'm missing something?

    • Reading from an uninitialized variable is UB, returning it is fine.

      • Anastasia

        But how can we prevent the user from reading it?

        • Add a comment to the constructor, stating that the array is uninitialized. If you don't trust the user with doing something they should be doing already, you can initialize the memory. If you don't want to initialize it, you can add a class that wraps the reference (as a pointer) and disallows writes if the variable is uninitialized. That way you'd have to keep track of which elements have been initialized, which adds a lot of overhead.

          • Anastasia

            I don't quite understand the last option you mentioned -- "you can add a class that wraps the reference (as a pointer) and disallows writes if the variable is uninitialized."
            Did you mean it disallows reading from it? Can you add a little example on how to do that or maybe I can read somewhere about it?

            • Yes, "disallows reading" not writing, my bad.
              While trying to write an example, I noticed that this is more complex than I thought and not reusable. It's not worth the effort. It's the user's job to look after their variables.

              • Anastasia

                I guess the easiest way to keep it safe then is to initialize the memory right away, like std::vector does (I think it does that). Thank you!

  • Sergey

    Hi! The author mentioned, "It is also worth explicitly mentioning that even though our sample IntArray container class holds a built-in data type (int), we could have just as easily used a user-defined type (e.g. a Point class)."

    Somebody, explain to me please, cause I don't quite understand, how we can do that unless we create a new container that holds Pointer data type?

    Thank a lot to the author. Best tutorial I have ever read!
    I wonder if there will be tutorials dedicated to other languages like this?))

  • noobmaster

    Suggestion : IntArray resize() function gives garbage values if newLength > m_length (example: change array.resize(8) in main() to array.resize(11)) and we try to print some indice that greater/equal than previous m_length. On the other hand, instead of garbage values, std::vector resize() gives 0. So I think its better to initialize that new array in IntArray resize() function with empty curly braces?

    Question : My compiler (VS 2019) gives warning at line 122 & 151 : Buffer overrun while writing to 'data': the writable size is '(m_length + 1)*4' bytes, but 'index'(line 122)/'8'(line 151) bytes might be written.
    What does it mean? And how to fix it?

    • > So I think its better to initialize that new array in IntArray resize() function with empty curly braces?
      If that's the behavior you want, yes.

      > What does it mean? And how to fix it?
      A buffer overrun occurs when you try to access an index that's larger than the maximum index of your array (eg. `array[11]` when the size of `array` is 8).
      Line 112 and 137 verify that the index is valid, no buffer overrun can occur. If asserts were disabled, your compiler would be right. See if you can disable that warning, I guess it will show up more often even if nothing is wrong.

  • Alex,

    I have a question I hope you can help me with. I am creating and using a model that involves two classes I will call class One and class Two. These are built into a model with a linked list of class Two objects with a Composition type relationship with the class One object. The number of class Two objects changes during the analysis by adding new objects into or at the end of the list and the member variables all change values constantly.
    At some points in the analysis I need to make a temporary exact copy of the entire model (structure and member data values). In the course of analysis using the temporary copy I will add more class Two objects into the temporary model and may as a result of the analysis add class Two objects into the original model. At the end of the analysis I will discard the temporary copy of the model.

    Sorry - I have a figure showing the model, but can't paste or build it into your comment space.

    My question, is there an easy way to create and populate the temporary duplicate model. The original model is all created dynamically. There is actually a parent class to the One object and its constructor dynamically (new) creates the One object. The constructor of the One object dynamically creates the linked list of Two objects. Some of the initial data for the Two objects is read from a data file during the construction process, including the number of Two objects in the list. This is implemented in a multiprocessing client server environment where the server and the clients all have multiple copies of this general model and the frequency of creating duplicate temporary copies is high. It would be nice if I could do this with something like
    temp = new One (copy all);
    – something like copying a folder and all sub-folders and pasting them somewhere else. Any suggestions?

  • Dars

    Why do we need erase() function?
    Since memory is deallocated using the destructor (~IntArray()) itself?

  • David

    Nascardriver, you often recommend using uniform initialization in every scenario. How do you recommend dealing with classes that have a constructor taking an std::initializer_list? Would you say that this is the only exception, and in such cases use parenthesis if the initializer list is not what you wish to invoke? This doesn't sit well with me because I would like a more general rule that doesn't have one very specific exception like this. What do you think of an idea like this: where brace initialization is used if the arguments are acting more or less as raw data, and using parenthesis if the arguments are acting as parameters for some logic that will be performed on the object?

    • Hi David!

      > Would you say that this is the only exception, and in such cases use parenthesis if the initializer list is not what you wish to invoke?

      Giving up implicit type safety (ie. no implicit casts) in favor of knowing if the constructor is performing extra operations isn't worth it in my opinion. I rarely use non-list constructors of types that offer list constructors, limiting the amount of exceptions i have to make.
      If you decide for Mike's rule, let me know and I'll stop telling you to use braced initializers everywhere.

      • David

        Thanks for the reply! I will try sticking with your rule because you're right that implicit type safety is probably most important in most cases. Still it bothers me some that C++ has this odd exception, but I will get used to it I'm sure.

  • hassan magaji

    hi Alex,
    thank you for this wonderful site. what amazed me the most is the implementation of your InArray class step-by-step which simplifies everything.

    however, i might have misunderstood the following statement:
     "...C++ generally does not allow you _to mix types inside a container_..."

    but how about std::tuple and std::variant, i think those can hold elements of mixed data types simultaneously in a single container.

    PS: thank you for these awesome tuts.

    • Alex

      Reworded as, "Unlike some other languages, many C++ containers do not allow you to arbitrarily mix types".

      There are a few that do, as you have mentioned. But unlike some scripting languages, which allow you to arbitrarily mix types, C++ requires strong typing, and mixing is generally only enabled through templatization.

  • Adriano Adriano

    I made a break with studying C++ because i was busy and this is more than hobby for me.
    Now I am trying to get back after 3 month break and i dont understand anything here, should i be worried and go back and repeat some lessons or should i skip this for now and i will understand it later.

  • Queen Elizabeth

    Hi Alex,

    what are you talking about when you write that the std::vector class wont always be possible?

    • Alex

      I didn't mean that -- I meant that every container class you might need isn't in the standard library, so you might need to write your own in such a case. I'll clarify the wording.

  • Saumitra Kulkarni

    Hi Alex

    I was creating container class myString (Probably useless since std::string will anyway provide almost all the functionality, but I was just fooling around.)

    So heres my myString.h

    • Saumitra Kulkarni

      May be due to size issues comment wasn't getting posted in its entirety so I split it in two

      The problem I faced was at this particular constructor :

      Since our parameter during initialization would be string literal I won't be able do something like this

      So I used so used the earlier constructor, It works fine but for that I have to individually copy ever character.
      So is there any better way around this?

      P.S. : If any errors, improvements or suggestions please let me know.

    • nascardriver

      Hi Saumitra!

      You have to use a const char* as parameter for your constructor. You also have to copy each character. Your second constructor only performs a pointer copy, that's bad.

      * Bad naming convention. Types, functions and some variables look alike.
      * Use uniform initialization
      * Your length constructor needs to allocate m_length+1 characters. You need a terminating 0.
      * Prefer ++prefix over postfix++
      * Line 37: A for loop is probably faster
      * If you don't want to modify a parameter, declare it const.
      * There's no point in declaring any of your member functions 'friend'. They have access to all private members anyway.

      * @operator+: @str won't be zero-terminated
      * @operator=: One char short, no zero terminator
      * @operator==: This can be done with one counting variable

      * @getLength: Could be declared 'inline' for performance. If you have getter and setter functions you should prefer them over direct access.
      * @uppercase: There are more characters after 'z'.
      * With characters: Prefer hexadecimal over decimal, prefer characters over hexadecimal

      * @lowercase: See @uppercase
      * @operator>>: You're neither freeing nor allocating @m_data
      * @operator>>: @i is unnecessary. Use @s.m_length directly.

      I guess you're doing this to get a better understanding of strings. If that's not the case and you just want some extra functionality you might want to have a look at all the @str* (@strlen, @strcpy, ...) functions or simply inherit from @std::string and add what you need.

      • Saumitra Kulkarni

        Thank you narscardriver for your feedback! So many silly mistakes, hope I don't make them next time.

      • Saumitra Kulkarni

        Also I observed that my operator+ only works when I don't provide my own copy and assignment constructors which does deep copying, In my class I haven't provided a copy constructor so when I later updated my class and added a copy constructor.

        Copy Constructor:

        The following code won't compile.

        I guess the problem had something to do with my operator+ returning it by value because anyways we cant return by reference due to local scope.

        So what is really happening underneath the hood?

        * Why does our code work with default copy constructor which does shallow copying?

        * Shouldn't our copy constructor work with the above case too? since when we execute something like this

        *To solve the problem I made str static in operator+ and returned by reference :

        This seemed to work.
        *Is there a better way than this ?

        Sorry for the troubles.

        • nascardriver

          What you did isn't a solution. When you create a second string using @operator+ is will be the same as the string created previously.

          "* If you don't want to modify a parameter, declare it const."

          Do this and your problems should be gone.

          • Saumitra Kulkarni

            Sorry but, could you please elaborate I updated the parameters to const and it still isn't working if I return by value.

            • nascardriver

              Two more things I noticed:
              * You're allowing zero-length arrays, that causes undefined behavior
              * @myString(const char*) and @operator+(const char*) are almost equivalent

              Here's a version with my suggestions and a working operator+

  • Srinivas

    You gave a great point

  • Benjamin


    in your reallocate(int newLength) function you are checking newLength. If it is smaller you just create an empty array. Wouldn't it be better to make such a check in the constructor IntArray(int length), too? Either by an assert or like

    Also I was thinking that it is dangerous not to assign values (zeros) to the array upon construction or when resizing with newLength > m_length to the elements with index >= m_length. Otherwise you will have garbage values in the array. If the user of IntArray tries to access elements of his container before assigning, he might get unexpected results. Well, it might also be unexpected, if he encounters zeros, but at least it is a bit more deterministic.

    While writing this question I encountered something funny about not initialized pointers. I am going to ask that the lesson about "new" and "delete".

    • Alex

      Yes, it would be better to assert or throw an exception in the case where the user passes in an invalid input. I've updated the example to either assert (if length is negative) or provide deterministic values (if length is 0).

      Thanks for the suggestion.


    2 Questions:
    (1) When you allocate a new memory for data

    Why didn't you deallocate it? wouldn't this cause a memory leak?

    (2) How do you delete a local variable dynamically allocated within a function


      I looked up but no answers. After like ~35 minutes of testing the code and checking for memory leaks with "Valgrind" I came up with these answers.



      • Alex

        > I think what confuses most beginners (including myself) is a & b are both dynamically allocated.

        No! The memory whose address is assigned to a is dynamically allocated. Pointers a and b are statically allocated on the stack. When function doSomething() ends, pointer a is destroyed, and the address of the dynamically allocated memory is returned and assigned to b. There's no leak here, simply a transfer between two pointers. If b was not deleted in main(), then the memory would be leaked because once b is destroyed, there's no other pointers to the dynamically allocated memory.


      Then how about these lines of code. They can compile but they don't run

      • Alex

        Same here. The memory allocated in line 4 is leaked when pointer b is reassigned to hold the same address as a.

        This will lead to undefined behavior, because b isn't pointing to dynamically allocated memory (it's pointing to the address of num, which was statically allocated).

    • Alex

      1) Keep in mind what this function is doing: Allocating a new array to replace the old one (which gets deleted). If we deleted the new array too, then the object wouldn't have an array to hold data.

      No memory leaks here either. Later on in the function, we set m_data = data, so m_data now points at the newly allocated memory, and because m_data is a member variable, it isn't destroyed or lost at the end of the function. When the class object is destroyed, the destructor will delete[] m_data, and the array will be deallocated then.

      2) delete a; within the same function.

  • Nur

    Hello Alex,
    I have a question. In 8.9 — Class code and header files's topic you quoted " we can put function declarations inside header files in order to use those functions in multiple files or even multiple projects. Classes are no different. Class definitions can be put in header files in order to facilitate reuse in multiple files or multiple projects".

    My question: Is this what you quoted above related to IntArray class.
    I mean, did you the create header file for IntArray class to use by other files or by other projects as well? i.e. Not only one file or project can be used container IntArray class and others as well, So the purpose of putting IntArray class in header file helps to reuse by other file or projects.Am I right?
    If i am not right here- could you explain? what is the purpose of putting the IntArray class in header file and main() for .cpp file separately?

    Thanks in advance!

  • KnowMore

    Alex? You haven’t deleted data pointer anywhere in the INT ARRAY class, so won’t there be memory leaks !?
    Shouldn’t You Do :-

    Instead of what you have done.. !?
    This also prevents memory leaks !
    Thanks For The Great Tutorials Anyway !
    Reply Plz

    • KnowMore

      Sorry, I realized that the above segment won't work.
      Let me come directly to my question,
      1) Why didn't you delete data pointer, Not deleting it wouldn't cause memory leaks?
      And My Second Question,
      What's the difference b/w :- ?


      I know that in the 1st case, they both would have same memory addresses and in the 2nd case, they would have diff. memory addresses.
      But still, the segment I asked you to replace doesn't work ! Help Plz !
      Thanks in Advance :)

      • KnowMore

        Oh God ! Why am I so confused?
        Sorry Alex !
        The segment that I asked you to replace actually worked perfectly !
        So, Now My Only Question is,
        You haven’t deleted data pointer anywhere in the INT ARRAY class, so won’t there be memory leaks !?
        Thanks ;)

        • Help

          He made a function called erase() that delete the data if needed and if the object dies he delete it with destructor.

          • KnowMore

            I am talking about data pointer not m_data pointer.
            Look Again :)

            • Help

              Sorry, my bad! But isn't m_data pointing at data ( m_data = data;) so they are both connected. Well im learning so im not the right person to give answer but what i understand is that m_data is later on assigned to point at same. so deleting m_data is same as delete data? so if we do several remove they keep stacking with point to point or maybe im just wrong but i think you got a point
              Well its better to wait for Alex answer :)

              • KnowMore

                You are actually right ! Don't Worry ! Thanks for Helping ! I'm also Learning !
                But, The thing is that I'm deep copying not shallow copying in this :-

                In this, even if i Delete data it doesnt affect m_data....

        • Alex

          No. We're doing 4 things in this code:
          * Dynamically allocating a new array (held by pointer data)
          * Copying the old array into the new array
          * Deleting the old array (held by m_data)
          * Setting m_data to point to the new array (m_data = data)

          We don't have a memory leak here because of this line:

          This sets m_data to point at the new array we created. If we deleted data, then m_data would be a dangling pointer, and our class would have unexpected behavior the next time we dereferenced m_data.

          • KnowMore

            Ah Yes ! I mis-understood it earlier !
            Is it that as we are deleting m_data, dynamically allocated contents of data pointer also get deleted !?
            Can't we do Deep-Copying Here Btw :-

            Thanks In Advance ! :)

            • Alex

              If we delete m_data, the contents of data also get deleted if and only if they are both pointing to the same thing.

              In your snippet of code, what does data represent?

              • KnowMore

                Exactly What I thought !
                data pointer is the extra ptr we created....
                I am deleting it explicitly (even though there is no need to), I just meant to ask That we can perform deep copying too there ! :)
                Thanks For The Help !!

  • Help

    When i run the code i get error do uk why? i copy paste the code and it gives me Assertion failed! index >= 0 && index < m_length.
    I copy pasted the code and it doesnt work

    By the way i have so much problem understanding when it comes to std::vector and std::vector when u use pointer to object in vector i get confused, any advice what knowledge i am missing? why use pointer to object and not just object?
    Thanks in advice:)

    • Help

      it supposed to say std::vector<object> and std::vector<*object>

      pointed object to vector and object to vector what is purpose for doing with point

    • Help

      I think i found the error! in ur insertBefore(int value, int index) when it calls insertAtEnd then u send insertBefore(int value, m_length) which will trigger the assert! so u need to have <= to be able to use the insertAtEnd to use that function!

      assert(index >= 0 && index <= m_length);

      • Alex

        Exactly right. I'd removed the equals sign in the index <= m_length check, but an index of m_length is actually valid here. I've updated the code to add it back in.

    • Alex

      Oops, my bad. I accidentally changed an assert I shouldn't have in response to a previous comment. It should be fixed now.

      You should use a pointer to an object when your objects aren't owned by the array/vector, or when your objects can't be created with a default constructor.

      • Help

        Thanks for the respond! About that pointer to object there is something i am missing cause it doesnt ring a bell for me, and it always makes me unsure. Do u got any advice where i should go back and read cause it feels like something i am missing. like the 10.4 why pointer to patient and doctor in std::vector everything else i understand just something i always struggle with

        Thanks in advice and thanks for the great guide its helps a lot :)

        • Alex

          Hmmm, I don't know if I've covered this topic anywhere explicitly. I updated lesson 10.4 to note that aggregations are normally implemented using pointers. In the doctor/patient example, we use Doctor and Patient pointers so that each can reference the other without implying ownership. If we tried to use normal members, it wouldn't work for many reasons. First, a Doctor doesn't have a Patient, so semantically the model is wrong. Second, if a Doctor included a Patient member and a Patient included a Doctor member, you'd get a circular reference that wouldn't compile. Third, a normal member confers ownership -- if a Doctor had a Patient member, when the Doctor was destroyed, the Patient would be too.

          So, generally speaking, with arrays/vectors, you use normal members when you're modelling compositions, and pointers when you're modeling aggregations or associations.

  • Omri

    " // If this is the last element in the erase, set the array to empty and bail out
            if (m_length == 1)
            } "
    I think this should be:
    //If there is a single element in the array and erase() will render it empty do the following:

  • Omri

    "void insertBefore(int value, int index)
            // Sanity check our index value
            assert(index >= 0 && index <= m_length);
    a. We require a valid index relating to the existing array.
        Why then allow index==m_length in index<=m_length?
    b. Sanity check... do you mean: relevance check?

    • Alex

      a) index >= m_length should be index > m_length. I've fixed that. Thanks for noticing the error.
      b) Same thing. It's a colloquialism for ensuring what we're doing makes sense.

  • Omri

    "We need to make sure we set m_data to 0 here, otherwise it will be left pointing at deallocated memory!"
    Should this not be:
    "We need to set m_data to *nullptr* here, otherwise it will be left pointing at deallocated memory!"
    And further on:
            m_data = nullptr; //instead of 0
            m_length = 0;

  • C++ Learner

    why delete[] m_data is written also inside erase function if it is already written inside destructor?

    • Alex

      So the user has a way to manually erase the data and reset the class back to a null state if they want to do that without destructing the object.

      • C++ Learner

        thanks :) can you say when destructor gets called in that code?
        The constructor is called when the object is created and destructor is called when object is destroyed, but what is the code that says the object is destroyed?

        • Alex

          It depends. Objects can get destroyed in a few ways:
          * If they have automatic duration (e.g. non-static local variables), at the end of the block they were declared in
          * If they have static duration, at the end of the program.
          * If they are allocated dynamically, whenever the user manually destroys them using the delete keyword.

  • Yifang Tan

    Hi Alex:
    I am trying to separate your example IntArray.h to header and body according to section 8.9, but always got error.
    Could it be possible for you, or anybody else, to correct my code?
    Thanks a lot!

    The header:

    And this is the body part:

    • Alex

      It looks like your functions in the header already have bodies:

      So the compiler is complaining that you're trying to redefine them in the code file.

      Update the functions in the header to not supply definitions:

      • Yifang Tan

        Thanks a lot!
        There are always too many options for any subject, which is the complexity of C++, so that similar but more concise tutorial is needed for beginners.
        Very good tutorials and thank you again!

  • The blinking amber light could mean a dead …..omg i would forget the nae#hm8230;.t&e part that you plug in the power cord! a major problem for the dell opiplex 745 atleast!

  • john

    Just two minor corrections:
    "This array class is going to be a value container, which will hold copies of the elements its organizing." - typo, its -> it's or it is.

    "And use the new array instead!  Note that this simply makes m_pnData point" - there is no m_pnData, var name is m_data.

Leave a Comment

Put all code inside code tags: [code]your code here[/code]