92
#include <iostream>
class Car
{
private:
  Car(){};
  int _no;
public:
  Car(int no)
  {
    _no=no;
  }
  void printNo()
  {
    std::cout<<_no<<std::endl;
  }
};
void printCarNumbers(Car *cars, int length)
{
    for(int i = 0; i<length;i++)
         std::cout<<cars[i].printNo();
}

int main()
{
  int userInput = 10;
  Car *mycars = new Car[userInput];
  for(int i =0;i < userInput;i++)
         mycars[i]=new Car[i+1];
  printCarNumbers(mycars,userInput);
  return 0;
}    

I want to create a car array but I get the following error:

cartest.cpp: In function ‘int main()’:
cartest.cpp:5: error: ‘Car::Car()’ is private
cartest.cpp:21: error: within this context

is there a way to make this initialization without making Car() constructor public?

Emil Laine
  • 41,598
  • 9
  • 101
  • 157
Dan Paradox
  • 1,350
  • 1
  • 11
  • 14
  • `operator new []` always invokes the default constructor. But C++11 has a solution, as shown [below](http://stackoverflow.com/a/35293931/485343). – rustyx Feb 09 '16 at 14:04

14 Answers14

83

You can use placement-new like this:

class Car
{
    int _no;
public:
    Car(int no) : _no(no)
    {
    }
};

int main()
{
    void *raw_memory = operator new[](NUM_CARS * sizeof(Car));
    Car *ptr = static_cast<Car *>(raw_memory);
    for (int i = 0; i < NUM_CARS; ++i) {
        new(&ptr[i]) Car(i);
    }

    // destruct in inverse order    
    for (int i = NUM_CARS - 1; i >= 0; --i) {
        ptr[i].~Car();
    }
    operator delete[](raw_memory);

    return 0;
}

Reference from More Effective C++ - Scott Meyers:
Item 4 - Avoid gratuitous default constructors

MAChitgarha
  • 3,728
  • 2
  • 33
  • 40
roxrook
  • 13,511
  • 40
  • 107
  • 156
  • 1
    Why you destruct in inverse order? – miniBill Jun 17 '12 at 18:57
  • 13
    @miniBill: Because it was constructed in forward order. The last thing constructed should be the first thing destructed. – Thomas Eding Jun 26 '12 at 19:41
  • 1
    @ThomasEding - the rule of thumb is needed to ensure the correct order of destruction for objects that are dependent on each other. In this particular case those objects have no dependencies so they can be destructed in the forward order which should be a little faster and cache friendly. Reverse iteration is usually very poor in terms of performance compared to forward iteration. – dtech Jun 28 '13 at 15:56
  • 7
    How can you make this solution exception safe? I.e., what if a constructor of Car throws an exception for some i? I suppose one has to catch the exception, deconstruct all already constructed Car's in reverse order and rethrow... – ingomueller.net Feb 21 '14 at 10:26
  • 7
    what will happen, if i do just `delete [] ptr;` at the end? – Youda008 Dec 18 '14 at 20:25
  • 1
    @Youda008 I'm curious as well. Do we have to call the destructors manually, or would the `delete[] ptr;` call it for us? – Sipka Feb 09 '15 at 21:10
  • 1
    @Sipka According to an experiment on VS 2015, that will lead to an endless loop. – cqdjyy01234 Sep 15 '15 at 02:27
  • 1
    OMG. That's some ugly piece of code. Don't do this. – rustyx Feb 09 '16 at 13:53
  • 1
    To make one thing clear: even if `delete[]` *did* work - in case of exception during construction, it would destruct the not yet created objects, too - undefined behaviour... – Aconcagua Mar 23 '18 at 09:49
  • that can crash on PowerPC / Itanium. Because `int` alignment requirement is 4, and raw_memory doesn't give much guarantee on that (depends on the allocator). It just so happens that the stdlib's `malloc` aligns to 16 so it works with almost everything. – v.oddou Apr 20 '18 at 06:37
  • 2
    The memory location returned by malloc and operator new is guaranteed to be suitably aligned so that it can be converted to a pointer of any complete object and accessed as array of objects. In other words, there is no alignment issue here. – vbraun Sep 01 '18 at 22:03
  • 1
    @Youda008 Using `delete[]` instead of `operator delete[]` (GCC 9.2.1), I experienced out-of-range iterations on calling destructors (and freeing memory, maybe), followed by a `free(): invalid pointer` error message. As @cqdjyy01234 mentioned, it causes an infinite loop thought. In my case, also, it is an infinite loop, however, it stops at some point because it cannot free an unknown pointer. Better to say, __don't use `delete[]`, as it's UB__. – MAChitgarha Mar 23 '20 at 13:11
  • cant you use char array instead of using a void pointer? – Matias Chara Jul 16 '20 at 14:00
  • and also, are the "[]" after the operator new and operator delete necesary, does it really need to be an array of void pointers? – Matias Chara Jul 17 '20 at 01:46
  • 1
    cplusplus.com shows an example of this too: `MyClass * p3 = (MyClass*) ::operator new (sizeof(MyClass));`. It states in the comments: `// allocates memory by calling: operator new (sizeof(MyClass)), but does not call MyClass's constructor`. See: http://www.cplusplus.com/reference/new/operator%20new/. – Gabriel Staples Aug 11 '20 at 02:44
54

Nope.

But lo! If you use std::vector<Car>, like you should be (never ever use new[]), then you can specify exactly how elements should be constructed*.

*Well sort of. You can specify the value of which to make copies of.


Like this:

#include <iostream>
#include <vector>

class Car
{
private:
    Car(); // if you don't use it, you can just declare it to make it private
    int _no;
public:
    Car(int no) :
    _no(no)
    {
        // use an initialization list to initialize members,
        // not the constructor body to assign them
    }

    void printNo()
    {
        // use whitespace, itmakesthingseasiertoread
        std::cout << _no << std::endl;
    }
};

int main()
{
    int userInput = 10;

    // first method: userInput copies of Car(5)
    std::vector<Car> mycars(userInput, Car(5)); 

    // second method:
    std::vector<Car> mycars; // empty
    mycars.reserve(userInput); // optional: reserve the memory upfront

    for (int i = 0; i < userInput; ++i)
        mycars.push_back(Car(i)); // ith element is a copy of this

    // return 0 is implicit on main's with no return statement,
    // useful for snippets and short code samples
} 

With the additional function:

void printCarNumbers(Car *cars, int length)
{
    for(int i = 0; i < length; i++) // whitespace! :)
         std::cout << cars[i].printNo();
}

int main()
{
    // ...

    printCarNumbers(&mycars[0], mycars.size());
} 

Note printCarNumbers really should be designed differently, to accept two iterators denoting a range.

GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • 3
    This actually does what I need but using vector is not an option. It must be Car because I have another method that takes *Car not std::vector – Dan Paradox Jan 21 '11 at 02:23
  • 4
    @Dan: You can use `&mycars[0]` to get a pointer to the underlying array. Though that's generally only useful for passing it to legacy code that doesn't use `std::vector`, you should update that requirement if you can. – GManNickG Jan 21 '11 at 02:24
  • Low level API's often take a buffer and sometimes they need to be large (for example, transferring data from a frame grabber). Sometimes you can't avoid it, but you're right in the vast majority of cases +1 – Ed S. Jan 21 '11 at 02:28
  • @Ed: Indeed. My guess is the requirement can change though, because I doubt the API really needs `Car*`. Maybe `void*`, though, and it was just loosely said. :) – GManNickG Jan 21 '11 at 02:30
  • @Gman @Ed The options are too bad. I have to either make Car() public or change the input parameter just to define an array of pointers – Dan Paradox Jan 21 '11 at 02:45
  • @Dan: What are you talking about? Did you see where I said you can use `&mycars[0]`? Why don't you make your question contain the *entire* problem so we can solve the entire thing? – GManNickG Jan 21 '11 at 02:48
  • @Gman sorry for confusion. I added a function printCarNumbers() that uses it. I hope it clarifies things. I don't wish to change parameters of printCarNumbers(). – Dan Paradox Jan 21 '11 at 03:00
  • @Dan: There's nothing wrong with the code you posted. Edit your question with the code you tried *and* the errors you get. Note that the line should be `printCarNumbers(&mycars[0], mycars.size());` and not `printCarNumbers(&mycars[0],userInput);`. While this happens to be the same in this example, what you want to pass is the size of the vector, so do that; just because they happen to be the same value *in this particular case* doesn't mean you should deviate from the more correct approach. – GManNickG Jan 21 '11 at 04:07
  • @Gman it is completely my mistake about compilation. I got it. Thank you. – Dan Paradox Jan 21 '11 at 04:40
  • 13
    Hey C'mon guys we have c++11 now instead of `&mycars[0]` let's use the equivalent `mycars.data()` that is oh so much more readable. – Russell Greene Oct 01 '15 at 04:18
  • 10
    I'm not an expert, but,-1 for the "never ever use new[]". It exists for a reason. – Matias Chara Jul 17 '20 at 02:32
  • Doesn't work when you want to initialize the array in the stack. You _could_ use some black magic to create an array of uninitialized values and then initialize them by hand, but otherwise it's hard to do. – JoaoBapt Jun 02 '21 at 14:16
  • Note: using `vector` does not work if the object being constructed is non-copyable. This is because even `emplace_back` may need to grow the buffer and copy the old data to the new location. I'm not aware of any way other than placement-new for that task. – jwd Sep 09 '22 at 15:51
26

You can create an array of pointers.

Car** mycars = new Car*[userInput];
for (int i=0; i<userInput; i++){
    mycars[i] = new Car(...);
}

...

for (int i=0; i<userInput; i++){
    delete mycars[i];
}
delete [] mycars;

or

Car() constructor does not need to be public. Add a static method to your class that builds an array:

static Car* makeArray(int length){
    return new Car[length];
}
Squall
  • 4,344
  • 7
  • 37
  • 46
8

In C++11's std::vector you can instantiate elements in-place using emplace_back:

  std::vector<Car> mycars;

  for (int i = 0; i < userInput; ++i)
  {
      mycars.emplace_back(i + 1); // pass in Car() constructor arguments
  }

Voila!

Car() default constructor never invoked.

Deletion will happen automatically when mycars goes out of scope.

rustyx
  • 80,671
  • 25
  • 200
  • 267
  • I'm facing a similar issue as OP, but my **mycars** contains a reference, so I cannot use emplace_back (as it would possible require use of the assignment operator, which doesn't exist since references are const). So, back to OP's original question, there's no way to instantiate each of the elements in an array by not using the default constructor? – mbrandalero Mar 13 '18 at 23:11
  • Why you require constructor call for array of references – PapaDiHatti Mar 23 '18 at 10:22
4

Good question. I had the same question, and found it here. The real answer is, @Dan-Paradox, there is no standard syntactical way of doing it. So, all these answers are a variety of alternatives to get around the problem.

I read the answers myself, and didn't particularly find any of them perfect for my personal convention. The method that I'll probably stick with is using a default constructor and a set method:

class MyClass
{
  int x,y,z;
public:
  MyClass(): x(0), y(0), z(0) {}
  MyClass(int _x,int _y,int _z): x(_x), y(_y), z(_z) {} // for single declarations
  void set(int _x,int _y,int _z)
  {
    x=_x;
    y=_y;
    z=_z;
  }
};

The standard initialization constructor is still there, so I can still initialize it normally if I don't need more than one, but if otherwise, I have a set method which sets all the variables that are initialized in the constructor. Thus I could do something like this:

int len = 25;
MyClass list = new MyClass[len];
for(int i = 0; i < len; i++)
  list[i].set(1, 2, 3);

This works fine and flows naturally, without making code look confusing.


Now that's my answer for those wondering how to declare an array of objects that need to be initialized.

For you specifically, you're trying to give an array of cars identities, which I'd suppose you want to always be unique. You could do it with my method I explained above, and then in the for loop use i+1 as the argument sent to the set method - but from what I've read in your comments, it seems like you want the ids more internally initiated, so that by default each Car has a unique id, even if someone else uses your class Car.

If this is what you want, you can use a static member:

class Car
{
  static int current_id;
  int id;
public:
  Car(): id(current_id++) {}

  int getId() { return id; }
};
int Car::current_id = 1;

// ...

int cars=10;
Car* carlist = new Car[cars];

for(int i = 0; i < cars; i++)
  cout << carlist[i].getId() << " "; // prints "1 2 3 4 5 6 7 8 9 10"

In this way, you don't have to worry at all about initiating the identities since they are managed internally.

MAChitgarha
  • 3,728
  • 2
  • 33
  • 40
Codesmith
  • 5,779
  • 5
  • 38
  • 50
  • 2
    You've made your class non-thread-safe by using static storage for the identity loop counter. If they only have to be unique within each collection, it makes more sense to use a local variable for the loop, for efficiency. There might not be a clean way to express that in C++, though, esp. not with the increment hidden inside the constructor. – Peter Cordes May 01 '16 at 03:12
4

No, there isn't. New-expression only allows default initialization or no initialization at all.

The workaround would be to allocate raw memory buffer using operator new[] and then construct objects in that buffer using placement-new with non-default constructor.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
4

Noboby have commented the posibility of using an allocator for this task.

#include <iostream>
#include <memory>

class Car
{
private:
  Car(){};
  int _no;
public:
  Car(int no)
  {
    _no=no;
  }
  void printNo()
  {
    std::cout<<_no<<std::endl;
  }
};

void printCarNumbers(Car *cars, int length)
{
    for(int i = 0; i<length;i++)
        (cars+i)->printNo();
}

int main()
{
  int userInput = 10;

  std::allocator<Car> carAllocator;

  // reserves space in memory for 10 car objects, but not construct them
  Car *myCars = carAllocator.allocate(10); 
  Car *myCarsBegin = myCars; // begin of array myCars

  for(int i =0; i < userInput; i++ ){
      // effectively creates the class "Car" and initializes it
      // myCars now points to the first car created
      carAllocator.construct( myCars, i );
      ++myCars;    
  }
  
  printCarNumbers(myCarsBegin,userInput);

  // destroy the objects created
  for( Car *carIterator = myCarsBegin; carIterator != myCars; ++carIterator )
      carAllocator.destroy( carIterator );

  return 0;
}
Raul Luna
  • 1,945
  • 1
  • 17
  • 26
3

You can always create an array of pointers , pointing to car objects and then create objects, in a for loop, as you want and save their address in the array , for example :

#include <iostream>
class Car
{
private:
  Car(){};
  int _no;
public:
  Car(int no)
  {
    _no=no;
  }
  void printNo()
  {
    std::cout<<_no<<std::endl;
  }
};
void printCarNumbers(Car *cars, int length)
{
    for(int i = 0; i<length;i++)
         std::cout<<cars[i].printNo();
}

int main()
{
  int userInput = 10;
  Car **mycars = new Car*[userInput];
  int i;
  for(i=0;i<userInput;i++)
      mycars[i] = new Car(i+1);

note new method !!!

  printCarNumbers_new(mycars,userInput);


  return 0;
}    

All you have to change in new method is handling cars as pointers than static objects in parameter and when calling method printNo() for example :

void printCarNumbers_new(Car **cars, int length)
{
    for(int i = 0; i<length;i++)
         std::cout<<cars[i]->printNo();
}

at the end of main is good to delete all dynamicly allocated memory like this

for(i=0;i<userInput;i++)
  delete mycars[i];      //deleting one obgject
delete[] mycars;         //deleting array of objects

Hope I helped, cheers!

2

One way to solve is to give a static factory method to allocate the array if for some reason you want to give constructor private.

static Car*  Car::CreateCarArray(int dimensions)

But why are you keeping one constructor public and other private?

But anyhow one more way is to declare the public constructor with default value

#define DEFAULT_CAR_INIT 0
Car::Car(int _no=DEFAULT_CAR_INIT);
Neera
  • 1,577
  • 8
  • 10
  • I made it Car() private because I want to avoid the copy constructor – Dan Paradox Jan 21 '11 at 02:20
  • 3
    @Dan: But that's not a copy constructor. – GManNickG Jan 21 '11 at 02:20
  • @GMan you are right but I want to avoid default constructor anyway. All cars must have an id – Dan Paradox Jan 21 '11 at 02:32
  • @Dan, In that case you can use the factory method with dimenions and initialization list. The factory method would be responsible for creating and array and initializing the id for each object. Initialization function can also be private. – Neera Jan 21 '11 at 02:55
2

Firstly I want to clarify that there is a bug in your code in printCarNumbers function, you are trying to send void to the standard output using std::cout as shown below :

void printCarNumbers(Car *cars, int length)
{
    for(int i = 0; i < length; i++)
         std::cout << cars[i].printNo();
}

since printNo() is used for printing then just call it directly:

for(int i = 0; i < length; i++)
   cars[i].printNo();

let's return to the subject, you are trying to allocate an array of objects using new like this :

Car *mycars = new Car[userInput];

but with this syntax, you actually trying to allocate an array of objects that has userInput size (well that's what we want), but the problem is that it tries to call the default constructor for each object, and the default constructor is declared as private, so it can't find it, that's why you got that error :

cartest.cpp:5: error: ‘Car::Car()’ is private

instead of that you need to do it in this way :

Car *mycars = (Car*) ::operator new (sizeof(Car));
// allocates memory by calling: operator new (sizeof(Car))
// but does not call Car's constructor

as described in the comments, calling new in this way, allocates memory for you without calling the default constructor, for more details check new operator

and now if you want to call the parametrized constructors, you need to call it for each object separately as the following :

for(int i =0; i < userInput; i++)
    new (&mycars[i]) Car(i + 1);  // does not allocate memory -- calls: operator new (sizeof(Car), &mycars[i])
                                  // but constructs an object at mycars[i]

you might be confused now, since we called new again, but this syntax for new is not allocating any memory, it's just calling the constructor of the indexed object.

and here is the full functioning code for anyone wants to test :

#include <iostream>

class Car
{
    private:
        Car(){};
        int _no;
    public:
        Car(int no)
        {
          _no=no;
        }
        void printNo()
        {
          std::cout << _no << std::endl;
        }
};

void printCarNumbers(Car *cars, int length)
{
    for(int i = 0; i < length; i++)
        cars[i].printNo();
}



int main()
{
  int userInput = 10;

  Car *mycars = (Car*) ::operator new (sizeof(Car));

  for(int i =0;i < userInput;i++)
    new (&mycars[i]) Car(i+1);

  printCarNumbers(mycars,userInput);

  return 0;
}

I know that I am so late, but maybe someone will find this useful, If there is any wrong statement, please be free to correct me.

Holy semicolon
  • 868
  • 1
  • 11
  • 27
1

You can use an array of optional<Car>, using optional from C++17.

#include <optional>

void printCarNumbers(std::optional<Car> *cars, int length) {
  for (int i = 0; i < length; ++i)
    cars[i]->printNo();
}

int main() {
  int userInput = 10;
  std::optional<Car> mycars[userInput];
  for (int i = 0; i < userInput; ++i)
    mycars[i].emplace(i);
  printCarNumbers(mycars, userInput);
  return 0;
}
dannyadam
  • 3,950
  • 2
  • 22
  • 19
0

My way

Car * cars;

// else were

extern Car * cars;

void main()
{
    // COLORS == id
    cars = new Car[3] {
        Car(BLUE),
            Car(RED),
            Car(GREEN)
    };
}
pacholik
  • 8,607
  • 9
  • 43
  • 55
0

I don't think there's type-safe method that can do what you want.

Dagang
  • 24,586
  • 26
  • 88
  • 133
0

You can use in-place operator new. This would be a bit horrible, and I'd recommend keeping in a factory.

Car* createCars(unsigned number)
{
    if (number == 0 )
        return 0;
    Car* cars = reinterpret_cast<Car*>(new char[sizeof(Car)* number]);
    for(unsigned carId = 0;
        carId != number;
        ++carId)
    {
        new(cars+carId) Car(carId);
    }
    return cars;
}

And define a corresponding destroy so as to match the new used in this.

Keith
  • 6,756
  • 19
  • 23