95
#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?

1
  • operator new [] always invokes the default constructor. But C++11 has a solution, as shown below. Commented Feb 9, 2016 at 14:04

15 Answers 15

88

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

Sign up to request clarification or add additional context in comments.

15 Comments

Why you destruct in inverse order?
@miniBill: Because it was constructed in forward order. The last thing constructed should be the first thing destructed.
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...
what will happen, if i do just delete [] ptr; at the end?
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.
|
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.

13 Comments

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<Car>
@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.
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
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.
I'm not an expert, but,-1 for the "never ever use new[]". It exists for a reason.
|
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];
}

1 Comment

This tends to be cleaner than the placement new option, BUT how about code that wants a Car * ?
10

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.

2 Comments

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?
Why you require constructor call for array of references
7

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;
}

1 Comment

I don't know why there is no up vote here, it is a simple and a good answer.
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.

4 Comments

Of course, we would use std::vector, which does this. But +1 for correctness.
How do I allocate raw memory with operator new[] ? Any link that explains that?
@Dan Paradox: There's an example in Chan's answer.
ITYM that the array form of new-expression only allows default-initialization, A *a = new A(args); is fine. Also this answer could be updated for C++11
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.

1 Comment

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.
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!

Comments

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);

4 Comments

I made it Car() private because I want to avoid the copy constructor
@Dan: But that's not a copy constructor.
@GMan you are right but I want to avoid default constructor anyway. All cars must have an id
@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.
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.

Comments

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;
}

Comments

0

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

Comments

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.

1 Comment

I would prefer not to use reinterpret_cast. That's why.
0

My way

Car * cars;

// else were

extern Car * cars;

void main()
{
    // COLORS == id
    cars = new Car[3] {
        Car(BLUE),
            Car(RED),
            Car(GREEN)
    };
}

1 Comment

Good for some few cases, but not portable. What if you have one hundred elements?
0

Since C++17, there is a portable way to do this, even for types requiring alignment. Here's a function that does what you want (requires C++17 or later for std::aligned_alloc):

// required headers
#include <cstdlib>
#include <type_traits>

// Return value must later be freed with std::free
template<class T>
T* allocUninitializedArray(std::size_t len) {
    auto alignment = std::alignment_of<T>();
    return static_cast<T*>(std::aligned_alloc(alignment, len*sizeof(T));
}

The code in your main function would then become

int userInput = 10;
Car *mycars = allocUninitializedArray<Car>(userInput);
for (int i = 0; i < userInput; i++) {
    new (&mycars[i]) Car(i);
}
printCarNumbers(mycars, userInput);
for (int i = 0; i < userInput; i++) {
    mycars[i].~Car();
}
std::free(mycars);
return 0;

Note that we also have to manually destruct each object in the array and then call std::free to free the actual array.

Explanation: The templated function allocUninitializedArray is able to access the alignment of T using std::alignment_of. We then use std::aligned_alloc to get the properly aligned array. This can be freed later with std::free.

At first, the returned array contains uninitialized memory of the correct size and alignment. Objects can be constructed in this array using placement new as you can see in the body of that for loop. Remember that new invokes the constructor, so for our code to be correct, we have to manually destruct each object in the array (with ~Car()).

Notes:

  • The simple Car class in the OP has a trivial destructor, so the compiler should optimize out the second for loop. However, if Car were a more complex class, then its destructor could be nontrivial (e.g. if it contained a std::string). In this case we need the second for loop or the code is incorrect.
  • Car also doesn't have specific alignment requirements, so the templated function is definitely overkill in this case, but again, the compiler will take care of this for us. Better to have a slightly more complicated function that works with all types.
  • Really, you can use any allocation functions you want as long as you can ensure alignment. I went with aligned_alloc and free because it's an easy and predictable way to get aligned memory. For instance, you could use operator new which also supports aligned allocation, but has the option to be globally replaced with custom allocation code, adding a new layer of complexity. You could even change allocUninitializedArray to take a custom allocator.
  • There are clever ways to accomplish a similar effect using containers (like std::vector with emplace_back (introduced in C++11) or reserve). However, those methods all incur some overhead in allocating and managing the container. If you really just need an array of objects, (e.g. if you're creating your own containers), then this is the most efficient method.
  • You could do this in an older version of C++ if you write your own aligned allocator (or use a library). There's nothing stopping you from writing a portable aligned allocator yourself in any version of C++, although the handy alignment_of template was only introduced in C++11.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.