1

Take the following example:

#include <iostream>
#include <stdio.h>
#include <vector>

using namespace std;

class Foo{
    public:
        Foo(){
            cout << "Constructing the default way..." << endl;
            this->num = (int*)malloc(sizeof(int));
        }
        Foo(int a){
            cout << "Using a custom constructor..." << endl;
            this->num = (int*)malloc(sizeof(int) * a);
        }

        ~Foo(){
            cout << "Destructing..." << endl;
            free((void*)num);
        }

        int* num;
};

int main()
{
    vector<Foo> objects(5);
    for(Foo& v : objects) printf("%x0x\n", v.num);

    cout << "\n---------------\n";
    cout << "END OF PROGRAM!\n";
    cout << "---------------\n\n";
    return 0;
}

Creating the vector by passing it an initial count of objects creates every single object individually, hence, all of them have their num at different addresses and their destructors are called at the end of the program.

However, if I want to create the vector by giving it a custom constructor like vector<Foo> objects(5, Foo(5)); (This is only my guess) a temporary object is constructed and then copied to every object in the array. Effectively, this makes every single object in the vector have their num pointer point to the same memory. Plus that memory gets freed when the initialization is finished and then every single object becomes useless.

How do I go around this without making the custom constructor into a new Init(int) function and running it on every single object in the vector? (Of course changing malloc into realloc).

Rokas Višinskas
  • 533
  • 4
  • 12
  • You may want [std::fill](https://en.cppreference.com/w/cpp/algorithm/fill). – Jesper Juhl Nov 11 '18 at 13:38
  • 2
    This question shows how you want to solve a problem. The problem with the question is that you don't tell us the *actual* problem you want to solve, you only ask us how to fix this solution to your unknown problem. That's a very typical [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). Please try to ask us about the real problem you want to solve, tell us your solution to it (which you have) and perhaps we will be able to help you solve the real problem in a perhaps better way. If not then we will help you with the solution you have. – Some programmer dude Nov 11 '18 at 13:39
  • 2
    Also, in C++ never use `malloc` and `free`, not even for primitive types like `int` arrays. Always begin with [`std::vector`](https://en.cppreference.com/w/cpp/container/vector). And you need to learn about [the rules of three/five/zero](https://en.cppreference.com/w/cpp/language/rule_of_three), and with a `std::vector` you can follow the rule of zero which I recommend. – Some programmer dude Nov 11 '18 at 13:42
  • 1
    `malloc`/`free` should never be used in C++ programs. They don't call constructors/destructors. Use `new`/`delete` instead - well, not really; please use containers and/or smart pointers instead of manual memory management. – Jesper Juhl Nov 11 '18 at 13:45
  • 2
    *This is only my guess* -- There is no need to guess. The `std::vector` implementation for your compiler is readily available to you by opening up the `#include ` header. Or simply debug and step through to see how that constructor works. In any event, it is likely that the `std::vector` class uses `placement-new`, not a naive "create a temporary and copy" as you would believe. The programmers writing the implementation of `std::vector` are some of the best professionals in the world -- they are well aware of optimizing these things far more than the average C++ programmer. – PaulMcKenzie Nov 11 '18 at 14:02

2 Answers2

1

You could solve your problem with a vector of unique_ptr's to the Foo objects.

class Foo
{
public:
    Foo(int i) {}

    // ...
};

#include <algorithm>
#include <vector>

auto main() -> int
{
    std::vector<std::unique_ptr<Foo>> foos(100);
    std::generate(foos.begin(), foos.end(), []() { return std::make_unique<Foo>(5); });
}

However, you don't want to do this because otherwise you would have to go the extra indirection with the unique_ptr when calling anything on a vector's Foo object.

As others have already suggested, you should store Foo's int members in a vector. Then you can just reserve the space in the vector and emplace_back (construct) your Foo objects directly in the vector of Foo's.

#include <vector>

class Foo
{
public:
    Foo() {}
    Foo(int i) : ints(i) {}

private:
    std::vector<int> ints;
};

namespace 
{
    constexpr auto NumberOfFoos = 100;
}

auto main() -> int
{
    std::vector<Foo> foos;
    foos.reserve(NumberOfFoos);

    for (auto i = 0; i < NumberOfFoos; ++i) {
        foos.emplace_back(10);
    }
}

Regarding your code, you might want to have a look at these additional sources and answers (as already suggested by other comments):

mostsignificant
  • 312
  • 1
  • 8
0

Two problems preventing a solution.

1) You need to implement your custom copy and assignment operators to do the deep copying since the default shallow copy (as you point out) doesn't do the right thing.

2) You need to let the object remember how large an array you are allocating for the copy/assignment implementations to work.

Bo R
  • 2,334
  • 1
  • 9
  • 17