Related
#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?
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
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.
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];
}
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.
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.
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.
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!
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;
}
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);
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.
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;
}
I don't think there's type-safe method that can do what you want.
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.
My way
Car * cars;
// else were
extern Car * cars;
void main()
{
// COLORS == id
cars = new Car[3] {
Car(BLUE),
Car(RED),
Car(GREEN)
};
}
#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?
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
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.
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];
}
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.
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.
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.
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!
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;
}
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);
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.
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;
}
I don't think there's type-safe method that can do what you want.
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.
My way
Car * cars;
// else were
extern Car * cars;
void main()
{
// COLORS == id
cars = new Car[3] {
Car(BLUE),
Car(RED),
Car(GREEN)
};
}
#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?
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
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.
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];
}
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.
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.
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.
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!
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;
}
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);
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.
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;
}
I don't think there's type-safe method that can do what you want.
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.
My way
Car * cars;
// else were
extern Car * cars;
void main()
{
// COLORS == id
cars = new Car[3] {
Car(BLUE),
Car(RED),
Car(GREEN)
};
}
How do i can free mamory in next example.
vt.pop_back() deletes element in vt, but it doesn't free memory.
delete vt[i] doesn't work, and it give me segmentation fault.
#include <vector>
#include <unistd.h>
using namespace std;
const int SIZE = 1000000;
class Test
{
public:
Test();
~Test();
private:
int *arr;
};
int main()
{
vector<Test *> vt;
for(int i = 0; i < 100; i++)
vt.push_back(new Test());
sleep(10);
return 0;
}
Test::Test()
{
arr = new int[SIZE];
}
Test::~Test()
{
delete[] arr;
}
You are not storing "Test" objects, you are storing pointers to these objects. So delete does nothing but delete the pointers.
If you want your objects to be stored in the vector you should make the type
vector<Test>
This way the delete calls actually run the destructor of the objects.
The resulting code becomes:
int main()
{
vector<Test> vt;
for(int i = 0; i < 100; i++)
vt.push_back(Test());
sleep(10);
return 0;
}
As commented this also requires a new copy constructor:
Test::Test(const Test& t)
{
arr = new int[SIZE];
for(int i = 0; i != SIZE; i++)
arr[i] = t.arr[i];
}
You can use delete vt[i] like this, it will free the memory allocated to Test objects:
for(size_t i = 0; i < vt.size(); ++i)
{
delete vt[i];
}
vt.clear();
You are storing pointers and not objects, therefor the "pointer object" is going to be destroyed if you destroy your vector but not the object the pointer points to
If you want to delete specific elements, you could try using the function erase of std::vector.
Okay. So I have declared an array of objects, and I have manually defined them using this code:
Object* objects[] =
{
new Object(/*constructor parameters*/),
new Object(/*constructor parameters*/)
};
Is there anyway to use some kind of a loop (preferably a for loop) to declare these? Something like:
Object* objects[] =
{
for(int i=0; i<20; /*number of objects*/ i++)
{
new Object(/*constructor parameters*/);
}
};
But with proper syntax?
I strongly suggest using a standard library container instead of arrays and pointers:
#include <vector>
std::vector<Object> objects;
// ...
void inside_some_function()
{
objects.reserve(20);
for (int i = 0; i < 20; ++i)
{
objects.push_back(Object( /* constructor parameters */ ));
}
}
This provides exception-safety and less stress on the heap.
Object* objects[20];
for(int i=0; i<20; /*number of objects*/ i++)
{
objects[i] = new Object(/*constructor parameters*/);
}
Points in C++ can be used as arrays. Try something like this:
// Example
#include <iostream>
using namespace std;
class Object
{
public:
Object(){}
Object(int t) : w00t(t){}
void print(){ cout<< w00t << endl; }
private:
int w00t;
};
int main()
{
Object * objects = new Object[20];
for(int i=0;i<20;++i)
objects[i] = Object(i);
objects[5].print();
objects[7].print();
delete [] objects;
return 0;
}
Regards,
Dennis M.