How do I switch both parameters of the class to the object that I am creating with a pointer? What is the syntax? (They must receive all the same parameters)
In a normal situation I use this:
MyClass obj[5]={MyClass(x,y)}
But... in this case what is the syntax? :
MyClass *obj;
obj = new MyClass[5]; //Here! <----
How can I pass the two parameters?
There is no syntax to list-initialize a dynamically allocated array.
You must
Either 1) default construct as in the example you show, and modify the objects after creation.
Or 2) allocate an array of char of sufficient size, and construct the objects with placement-new.
1) is not an option if the class is not default constructible. 2) is a bit complicated, but you don't have to do that yourself since std::vector has already implemented it for you. You should be using vector anyway since it takes care of memory management.
An example with vector, that is analogous to your "normal situation". Note that your "normal situation" doesn't match the description in your question:
std::vector<MyClass> v{
{x1, y1},
{x2, y2},
...
};
An example with vector, that matches your description of passing same argument to all objects in the array. Although technically, this copy-constructs the array elements:
std::vector<MyClass> v(5, {x, y});
I'm assuming that your question is: "how do I initialize all the objects in an array with the exact same constructor call?"
If that's the case, the easiest way of doing so is using std::vector's constructor (2):
vector( size_type count,
const T& value,
const Allocator& alloc = Allocator());
Constructs the container with count copies of elements with value value.
Your example then becomes:
std::vector<MyClass> obj(5, MyClass{x, y});
If you really want to use a C-style array, you will have to manually invoke constructors using placement new and manually invoke destructors if you want to avoid unnecessary default constructor calls. Example:
std::aligned_storage_t<sizeof(MyClass), alignof(MyClass)> obj[5];
for(auto& x : obj) { new(&x) MyClass{x, y}; }
// ... use `obj` ...
for(auto& x : obj) { reinterpret_cast<MyClass*>(&x)->~MyClass(); }
Note that the above code can be (and should be) refactored into a safe abstraction.
Related
I want an array of class objects with unique_ptr:
std::unique_ptr<MyClass[]> arr(new MyClass[n]);
MyClass has no default constructor (and in my case is not supposed to have), so I have to put it explicitly here. I cannot find out how to do it so it is syntactically correct. What is the correct way to write a unique_ptr array of class objects with explicit initialisation?
Clarification
I have a non-default constuctor for MyClass, like this:
MyClass instance(arguments);
Apart from member initialisations, there are also some calculations in the constructor. I want to create a unique_ptr array of MyClass instances and call the constructor for each of the instances. I cannot do that later since MyClass has no default constructor. Can I put (arguments) somewhere in std::unique_ptr<MyClass[]> arr(new MyClass[n])?
The answer below is based on a previous version of the question, in which the array size appeared to be a compile-time constant. If the size of the created array is not a compile-time constant, then it is impossible to pass arguments to the constructors of the elements. In that case std::vector is probably a better choice than array-std::unique_ptr.
It works the same as always for arrays, using aggregate initialization:
std::unique_ptr<MyClass[]> arr(new MyClass[]{
{...},
{...},
{...},
{...},
{...}});
where ... are replaced by the argument lists for the constructors of the five elements.
Or if you cannot use list-initialization for the elements, e.g. because that would unintentionally use a std::initializer_list constructor:
std::unique_ptr<MyClass[]> arr(new MyClass[]{
MyClass(...),
MyClass(...),
MyClass(...),
MyClass(...),
MyClass(...)});
std::make_unique would usually be preferred for creating std::unique_ptrs, but there is at the moment no overload which allows passing arguments to the constructors of the individual array elements.
If you want to pass the same argument list to each element, a simple solution given that the type is copy-constructible would be to declare one instance and then copy-construct the elements from this instance:
MyClass instance(arguments);
std::unique_ptr<MyClass[]> arr(new MyClass[]{instance, instance, instance, instance, instance);
Otherwise you could write a template function that expands these repeated items for you. (Might add example later.)
I have some objects of a same class in an array that was pointed by a unique_ptr,
and each object can only be created with the explicit constructor, since a few of arguments must be passed to the constructor.
When initializing, I'm going to create such a unique_ptr as following:
unique_ptr<ClassA [ ] > arrayA = make_unique<ClassA [ ]>(100, some args to be passed );
But it looks like there is no version of make_unique can do so as above.
According to docs: If make_unique is making a array, it only takes one argument that is the size of the array.
I can not use vector in this scenes, as the ClassA is a message queue that is being shared by multiple threads(productors/cosumers),
while vector will move elements to a new place if the space is insufficient.
Is there another way, in it I can make a array of a class that has only explicit constructor?
At same time, I still want to use unique_ptr to manage them.
Thanks!
You don't have to use make_unique, you can construct the pointer and pass some manually allocated memory.
class ClassA {
public:
int a;
float b;
};
const auto x = std::unique_ptr<ClassA[]>{new ClassA[2]{{1, 2}, {1, 2}}};
I think the idea propsed by #AchimGuetlein is better.
Define as following:
vector<unique_ptr<ClassA> > container;
for (i = 0; i<number of queues; ++i)
container.emplace_back(make_unique<ClassA>(args to constructor of ClassA));
instead of :
unique_ptr<ClassA [] > ques = make_unique<ClassA [] >(n, ...);
Although elements of vector might be moved, there is no moving occured to my queues. The objs moved just are unique_ptr self, but the addresses of the queues would never be changed.
Sorry for committing it as an answer, since the code sample can not be gracefully showed as codelet in a comment.
I have a class lets say aClass
class aClass
{
public:
int data;
aClass(): data(-1) { //default constructor
}
aClass(int x): data(x) { //int constructor
};
If I create an array like
aClass* arr=new aClass[10];
Question 1:
I was thinking no aClass object has been created since it is just a declaration of an array, but in a program that I tested it looks like arr[0] to arr[9] all points to a aClass object created by default constructor in its class? Because I had tested the program and the result is a[0].data=-1 all the way to a[9].data=-1.
Question 2: if objects are created with their default constructor, how am I supposed to create an array that has objects created by int constructor? obviously I can't write code like
aClass* arr=new aClass(2015)[10];
Quesntion 1: I was thinking no aClass object has been created since it is just a declaration of an array
You were thinking wrong. It's a declaration of a pointer which is initialized with the return value of new aClass[10] which constructs an array of 10 objects.
but in a program that I tested it looks like arr[0] to arr[9] all points to a aClass object created by default constructor in its class?
Yes, your observation is correct.
Question 2: if objects are created with their default constructor, how am I supposed to create an array that has objects created by int constructor?
Since c++11 you can use list initialization: aClass *foo = new aClass[3]{1, 2, 3}; as chris pointed in a comment.
You may want to use std::vector instead. There is std::vector::vector(size_type n, const value_type& val) for constructing copies and since c++11: std::vector::vector(initializer_list<value_type>) for different values.
With static/automatic arrays aggregate initialization was possible even before c++11:
aClass foo[3] = { 1, 2, 3 };
Instead of aClass* arr=new aClass(2015)[10];
You could do aClass *arr = new aClass[10]{2015, 2015/*etc*/}; if your compiler supports it.
In C++11, both of these mean the same thing.
aClass *arr = new aClass[10];
aClass *arr = new aClass[10]{};
Better alternative would be to use std::vector and avoid using raw pointers and instead use smart pointers ex. std::unique_ptr.
Example of this alternative could be:
int main()
{
vector<unique_ptr<aClass>> vec;
for (int i{0}; i != 10; ++i)
vec.emplace_back(new aClass(2015));
for (auto const& i : vec) // print data
cout << i->data << endl;
return 0;
}
Regarding question 1. The rules for initialization are very rigid. Your array new[] expression creates an array of values. Those values must be initialized and by default they use default initialization.
The answer to question 2 is that you can't do that with dynamic arrays. However, std::vector does provide a constructor that allows you to provide an object that will be copied to each of the contained elements. See explicit vector(size_type count, const T& value = T(), const Allocator& alloc = Allocator()).
If you want each element in the collection to be different, then you must use a loop and assign the elements individually unless the size of the array is determined statically in which case you can use initializer expressions. If you want to avoid the initial default construction for dynamic containers, then you should not store the objects by value. You should use a container of pointers or better yet a container of smart pointers. Then you can use direct initialization for each object.
You need to create array of pointers if you want to create an array without creating the objects. For example, aClass** arr = new aClass*[10]; creates an array of pointers. And when you want to create the actual objects, you need to do something like this: arr[0] = new aClass(2015);
Say I have a class called Foo. Foo doesn't have a default constructor. It has a constructor Foo(int x, float y).
Bar is a container class. It contains a vector that contains instances of Foo.
Bar::Bar(int numberOfFoos, int x, float y) {
foovector.resize (numberOfFoos);
for(int i = 0; i < numberOfFoos; i++) {
**read below**
}
at this point, I want to call the constructor of Foo and pass to it the parameters int x and float y. The constructor of Foo does different things depending on the value of x and y.
Let's say Foo had a default constructor, what exactly does the resize vector function do? Does it simply resize the vector without calling the default constructor? In other words, is space reserved for n elements of type Foo but they aren't initialized to anything??
What if it doesn't have one, like in this case?
in the for loop I want to initialize each Foo element in this way:
foovector[i].Foo(int x, float y);
but I can't call the constructor using the dot access operator in this way. I don't even know at this point if the constructor has already been called by the resize function or not.
Question is, how can I do it?
Another related question about vectors of classes:
In Foo there is a vector that holds floats. the float x parameter is the number of floats that it should hold. Foo's constructor has a line
arrayofFloats.resize (x);
But that means that the computer doesn't know beforehand the size of Foo. And each foo can have different size. Wouldn't it cause problems for a vector of Foo's? How can a vector of specific size be declared if each Foo can have different size?
Sorry for bad english, I hope it has been clear enough.
Thank you.
Don't use resize to reserve space. Instead, use reserve:
foovector.reserve(n); // reserves memory only, no object
// constructions take place
for (std::size_t i = 0; i != n; ++i)
{
foovector.emplace_back(12 * i, i / 3.0); // pushes a new Foo(12*i, i/3.0)
} // at the back of the vector
If I understand this right, you want the Bar constructor to construct numerous instances of Foo within a vector with the same arguments to the Foo constructor each time. IF the Foo constructor works in such a way that the Foo objects will all be identical after construction, you can use std::vector::assign(size_type n, const value_type& val), where value_type in this case is Foo. If you call foovector.assign( numberOfFoos, Foo(x, y) ), the vector will construct one temporary Foo object and fill itself with numberOfFoos copies of that object. assign() also handles all your resizing needs.
But if the Foo constructor involves random behavior, static counters, or something else that causes successive calls to the constructor to result in different objects, copying is not what you want.
Your other question:
In C++, every type has a fixed size. (This is why polymorphism only works with pointers or pass-by-reference semantics.) Many classes, such as std::vector, manage additional memory which can grow or shrink as needed. This is all done behind the scenes with pointers. Additional memory, such as the data contained by a vector, is off in some other memory location and does not affect the actual
size of the object. The vector methods size(), resize(), and reserve() work with that managed memory. So a Foo object is the same size no matter how many items are in its vector.
resize does initialise the new elements; specifically, it value-initialises a temporary object (using the default constructor, if it's a class type), then copy-initialises each element using that.
If it doesn't have a default constructor, or can't be copy-initialised, then you can't use resize.
However, you can use reserve to reserve memory without initialising any objects in it; and then use push_back or insert elements into that space. In C++11, you can also use emplace_back to avoid the need to copy elements:
foovector.reserve (numberOfFoos);
for(int i = 0; i < numberOfFoos; i++) {
foovector.push_back(Foo(42, 1.23)); // C++03, requires copy constructor
foovector.emplace_back(42, 1.23); // C++11, doesn't require copy constructor
}
Regarding your extra question:
But that means that the computer doesn't know beforehand the size of Foo
Yes it does. A vector is a small object containing a pointer to some dynamically allocated memory; its size is fixed, and does not depend on how much memory it allocates.
I noticed that when you declare an array, the default constructor must be needed. Is that right?
Is there any exception?
For example,
struct Foo{
Foo(int i ) {}
};
int main () {
Foo f[5];
return 0;
}
The code above does not compile.
Other answers are all right but, for completeness: You could also use the array initialization syntax:
Foo f[5] = {1,2,3,4,5};
This works if Foo's ctor is not explicit. If it was, you'd have to be.... explicit:
Foo f[5] = {Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)};
Note1: There is a difference between the two cases that may not be obvious and is thus worth noting: In the first, the array elements are directly constructed from the ints in the initialization list, by invoking the Foo(int) ctor. In the second, the initialization list is made of Foos constructed with the explicit Foo(int) ctor, and the array elements are copy constructed from the elements in the initialization list. A copy ctor for Foo is thus required in the latter case.
[1] Thanks to MSalters for the comment.
The issue has nothing to do with arrays at all.
When you default-initialize an object of class type, the default constructor is required. If your class has no default constructor, then you have no other choice but to supply an explicit initializer when creating objects of that class. That's all.
By declaring a non-default constructor in your class Foo, you disabled the implicit generation of the default one, so now you'll have to supply an initializer every time you create a Foo object, regardless of whether it is an array element or not.
This declaration
Foo f; // ERROR
is not an array, but it will not compile for the very same reason. In order for it to compile you'll have to supply an explicit initializer
Foo f(3); // OK
The same thing happens with array, except that in that case you have to supply an initializer for each element using the aggregate initializer syntax
Foo f[5] = { 1, 2, 3, 4, 5 };
Of course, if you end up in a context where aggregate initializer syntax is not allowed (in the current version of C++ standard), like constructor initializer list or new-expression, then you are indeed screwed. In such contexts the only way out is to provide the default constructor in array element type (as long as you stick with built-in arrays).
That code doesn't compile because the compiler doesn't know what you want to pass to the constructor of each element, of course. There are basically two ways to go about it:
Make the array a vector, and pass it the desired size plus a single element -- this gives each element the same argument.
Make the array an array of pointers, and construct each element using a for loop and the new operator. The drawback of course, is that you have to free each element later as well.
See the C++ FAQ Lite, section 10.5
When you create an array, the default constructor gets called for each element in the array.
"If your class doesn't have a default constructor, you'll get a compile-time error when you attempt to create an array "
Prefer to use std::vector instead of the built-in arrays, though.
There is no exception. In what could be seen as exception, there is a compiler declared default constructor.
Note that a default constructor is not required if you use std::vector instead of an array - you can specify the constructor to be used:
std::vector <Foo> f; // OK
std::vector <Foo> f( 5, Foo(0) ); // also OK
No it doesn't.
An array, in C/C++ is a block of memory. Creating an array is reserving that block. Creating the objects is "1. Allocating the space 2. Running the constructors on each block" So, if you have an object without a constructor, you can still make an array of it (since that object has a size and since memory understands "size").
In short, it doesn't make any difference whatsoever. You will be running the constructors as you create the objects to fill the array with, or as said previously, when you assign it to something (which in turn, allocates space, runs the constructor).
Yes, you need the default constructor here because Foo f[5]; actually creates 5 Foos. You can work around this by making it a Foo* f[5] and then creating the 5 Foos with new.
For example:
Foo* f[5];
for(int i = 0; i < 5; ++i) {
f[i] = new Foo(i);
}
// later on...
f[0]->whatever();
Warning: slightly off-topic.
If you have a class without default constructor, you absolutely need to have an array, and you don't want to incur into the overhead of dynamic memory allocation, you can use an array of boost::optionals:
boost::optional<Foo> foos[4]; // Stack storage allocated but no objects
// constructed (roughly equivalent to what
// you get with vector<T>::reserve)
if(foos[2]) // Check if the third element has been constructed
{
foos[2]->bar(); // Access members of Foo with arrow
}
foos[1] = Foo(1, "a"); // Constructs the second element
foos[1].reset(); // Destroy second element (storage remains there though)
Unfortunately, you won't be able to pass this to a function expecting a true Foo[].