How C++ call parameterized ctor to create object arrays? - c++

I know in c++11 I can use initializer to create array/vector elements one by one like:
int ar[10]={1,2,3,4,5,6};
vector<int> vi = {1,2,3,4};
This is done manually, but what if I wish to initialize an array/vector with 10000 elements and specify their value, can it be done in one statement, RAII pattern?
E.g. I've defined a class:
class Somebody{
int age;
string name;
public:
Somebody():age(20),name("dummy"){} // default ctor
Somebody(int a, const char* n):age(a),name(n){} // but I wish to call this ctor
Somebody& operator = (const Somebody& s) {...}
};
Then in main function:
int main(int argc, char const *argv[])
{
Somebody obj(2, "John"); // parameterized ctor
Somebody ar[300]; // initialized, but called default ctor
for(int i=0;i<300;++i){ // initialize again in a loop
ar[i] = ... ; // call operator =
...
Question: could Somebody ar[300] be constructed with parameterized ctor?
If not, then I have to create this object array ar first(Compiler generated code will loop and call default parameter), then apply value changes for each object. This seems quite a bit redundant of cpu cycles.
Is there a way to do what I expected with just one call? (Loop and update each array element with parameterized ctor)
Thanks.

You can not do this with C-style arrays. One of the many reasons you should not be using them in the first place.
You should be using std::vector, which provides a constructor to populate the vector using a single value:
std::vector<Somebody> ar{300, Somebody("42", "filler")};
But often it is better to not create such dummy entries in the first place. A std::vector can grow dynamically so you can just add Somebody objects to it as you get their age and name.
std::vector people;
people.reserve(2); // optional but makes adding lots of objects more efficient
Somebody adam(42, "Adam");
people.push_back(adam);
people.emplace_back(23, "Eve");
This shows you 2 ways to add objects to the vector, the push_back adds objects to the vector (copies/moves it) while emplace_back will construct the object directly in the vector, which is often more efficient.
If you want a fixed size array then you can use
std::array<Somebody, 300> ar;
ar.fill(Somebody(23, "filler"));
But this has the same problem as the C-style array of using the default construtor. std::arrays::fill replaces all the objects with a new value.
Unfortunately there is no array constructor to do this in one go which is rather unfortunate.

Well, with simple arrays there's always the direct approach:
Somebody ar[300]={ {1, "Larry"}, {2, "Moe"}, {3, "Curly"} ... };
You'd have to write out whatever you want to write out 297 more times. This gets real old, real quickly.
One could potentially concoct, in a pinch, something that involves a variadic template to generate the whole bunch of them. Something like that is the classical approach to generating a fast 256-value array lookup for a textbook-style base64 decoder.
But for the simplistic case where you only want the same value, just #n copies of it, the simplest solution is to use a std::vector instead of a plain array and use one of its contructors that takes a single object and the vector size, and then constructs the vector by copying the object the requisite number of times. That involves slightly more overhead but is generally good enough, for this simple use case.

You can use std::fill_n:
Somebody obj(2, "John");
Somebody ar[300];
fill_n(ar, 300, obj);

Related

C++ function error in parameter: expression must have a constant value [duplicate]

I have this method:
void createSomething(Items &items)
{
int arr[items.count]; // number of items
}
But it's throwing an error:
expression must have a constant value
I found just this solution:
int** arr= new int*[items.count];
so I'm asking is there a better way how do handle this?
You can use a std::vector
void createSomething(Items &items)
{
std::vector<int> arr(items.count); // number of items
}
The reason your first method won't work is that the size of an array must be know at compile time (without using compiler extensions), so you have to use dynamically sized arrays. You can use new to allocate the array yourself
void createSomething(Items &items)
{
int* arr = new int[items.count]; // number of items
// also remember to clean up your memory
delete[] arr;
}
But it is safer and IMHO more helpful to use a std::vector.
Built in arrays & std::array always require a constant integer to determine their size. Of course in case of dynamic arrays (the one created with new keyword) can use a non-constant integer as you have shown.
However std::vector (which of course internally a dynamic array only) uses a is the best solution when it comes to array-type applications. It's not only because it can be given a non-constant integer as size but also it can grown as well as dynamically quite effectively. Plus std::vector has many fancy functions to help you in your job.
In your question you have to simply replace int arr[items.count]; with :-
std::vector<int> arr(items.count); // You need to mention the type
// because std::vector is a class template, hence here 'int' is mentioned
Once you start with std::vector, you would find yourself preferring it in 99% cases over normal arrays because of it's flexibility with arrays. First of all you needn't bother about deleting it. The vector will take care of it. Moreover functions like push_back, insert, emplace_back, emplace, erase, etc help you make effective insertions & deletions to it which means you don't have to write these functions manually.
For more reference refer to this

Why is there no emplace or emplace_back for std::string?

I'm pretty sure I've seen this asked on here before, but I can't seem to find the post when I tried searching, and I don't recall the answer.
Why is there no emplace or emplace_back for std::string?
I don't think it's related to the use of char, since you can have a vector of chars, and there's no problem with emplace_backing a char in the vector.
There would be no gain over push_back
The power of emplace_back is that it constructs an object in-place, where it is designed to stay. No copies or moves are needed. And it also provides simpler syntax for creating objects, but that's just a minor advantage.
class Person
{
std::string name;
int age;
double salary;
}
int main()
{
std::vector<Person> people;
people.push_back(Person{"Smith", 42, 10000.0}); //temporary object is needed, which is moved to storage
people.emplace_back("Smith", 42, 10000.0); //no temporary object and concise syntax
}
For std::string (or any theoretical container that can only hold primitive types), the gain is nonexistent. No matter if you construct object in place or move it or copy it, you perform the same operation at assembly level - write some bytes at given memory.
Syntax also cannot become more concise than it is - there is no constructor that needs to be called. You can use a literal or another variable, but you have to do exactly same thing in both push_back and emplace_back
int main()
{
std::vector<char> letters;
letters.push_back('a');
letters.emplace_back('a'); //no difference
}
The advantage of (e.g.) std::vector‹T>::emplace_back is that it constructs an object of type T directly in the vector, instead of constructing a temporary and then copying it in.
Since char is a primitive type, there is no advantage in one method over the other, so there is no reason for std::string::emplace_back to exist.

c++ expression must have a constant value

I have this method:
void createSomething(Items &items)
{
int arr[items.count]; // number of items
}
But it's throwing an error:
expression must have a constant value
I found just this solution:
int** arr= new int*[items.count];
so I'm asking is there a better way how do handle this?
You can use a std::vector
void createSomething(Items &items)
{
std::vector<int> arr(items.count); // number of items
}
The reason your first method won't work is that the size of an array must be know at compile time (without using compiler extensions), so you have to use dynamically sized arrays. You can use new to allocate the array yourself
void createSomething(Items &items)
{
int* arr = new int[items.count]; // number of items
// also remember to clean up your memory
delete[] arr;
}
But it is safer and IMHO more helpful to use a std::vector.
Built in arrays & std::array always require a constant integer to determine their size. Of course in case of dynamic arrays (the one created with new keyword) can use a non-constant integer as you have shown.
However std::vector (which of course internally a dynamic array only) uses a is the best solution when it comes to array-type applications. It's not only because it can be given a non-constant integer as size but also it can grown as well as dynamically quite effectively. Plus std::vector has many fancy functions to help you in your job.
In your question you have to simply replace int arr[items.count]; with :-
std::vector<int> arr(items.count); // You need to mention the type
// because std::vector is a class template, hence here 'int' is mentioned
Once you start with std::vector, you would find yourself preferring it in 99% cases over normal arrays because of it's flexibility with arrays. First of all you needn't bother about deleting it. The vector will take care of it. Moreover functions like push_back, insert, emplace_back, emplace, erase, etc help you make effective insertions & deletions to it which means you don't have to write these functions manually.
For more reference refer to this

C++ New vs Malloc for dynamic memory array of Objects

I have a class Bullet that takes several arguments for its construction. However, I am using a dynamic memory array to store them. I am using C++ so i want to conform to it's standard by using the new operator to allocate the memory. The problem is that the new operator is asking for the constructor arguments when I'm allocating the array, which I don't have at that time. I can accomplish this using malloc to get the right size then fill in form there, but that's not what i want to use :) any ideas?
pBulletArray = (Bullet*) malloc(iBulletArraySize * sizeof(Bullet)); // Works
pBulletArray = new Bullet[iBulletArraySize]; // Requires constructor arguments
Thanks.
You can't.
And if you truly want to conform to C++ standards, you should use std::vector.
FYI, it would probably be even more expensive than what you're trying to achieve. If you could do this, new would call a constructor. But since you'll modify the object later on anyway, the initial construction is useless.
1) std::vector
A std::vector really is the proper C++ way to do this.
std::vector<Bullet> bullets;
bullets.reserve(10); // allocate memory for bullets without constructing any
bullets.push_back(Bullet(10.2,"Bang")); // put a Bullet in the vector.
bullets.emplace_back(10.2,"Bang"); // (C++11 only) construct a Bullet in the vector without copying.
2) new [] operator
It is also possible to do this with new, but you really shouldn't. Manually managing resources with new/delete is an advanced task, similar to template meta-programming in that it's best left to library builders, who'll use these features to build efficient, high level libraries for you. In fact to do this correctly you'll basically be implementing the internals of std::vector.
When you use the new operator to allocate an array, every element in the array is default initialized. Your code could work if you added a default constructor to Bullet:
class Bullet {
public:
Bullet() {} // default constructor
Bullet(double,std::string const &) {}
};
std::unique_ptr<Bullet[]> b = new Bullet[10]; // default construct 10 bullets
Then, when you have the real data for a Bullet you can assign it to one of the elements of the array:
b[3] = Bullet(20.3,"Bang");
Note the use of unique_ptr to ensure that proper clean-up occurs, and that it's exception safe. Doing these things manually is difficult and error prone.
3) operator new
The new operator initializes its objects in addition to allocating space for them. If you want to simply allocate space, you can use operator new.
std::unique_ptr<Bullet,void(*)(Bullet*)> bullets(
static_cast<Bullet*>(::operator new(10 * sizeof(Bullet))),
[](Bullet *b){::operator delete(b);});
(Note that the unique_ptr ensures that the storage will be deallocated but no more. Specifically, if we construct any objects in this storage we have to manually destruct them and do so in an exception safe way.)
bullets now points to storage sufficient for an array of Bullets. You can construct an array in this storage:
new (bullets.get()) Bullet[10];
However the array construction again uses default initialization for each element, which we're trying to avoid.
AFAIK C++ doesn't specify any well defined method of constructing an array without constructing the elements. I imagine this is largely because doing so would be a no-op for most (all?) C++ implementations. So while the following is technically undefined, in practice it's pretty well defined.
bool constructed[10] = {}; // a place to mark which elements are constructed
// construct some elements of the array
for(int i=0;i<10;i+=2) {
try {
// pretend bullets points to the first element of a valid array. Otherwise 'bullets.get()+i' is undefined
new (bullets.get()+i) Bullet(10.2,"Bang");
constructed = true;
} catch(...) {}
}
That will construct elements of the array without using the default constructor. You don't have to construct every element, just the ones you want to use. However when destroying the elements you have to remember to destroy only the elements that were constructed.
// destruct the elements of the array that we constructed before
for(int i=0;i<10;++i) {
if(constructed[i]) {
bullets[i].~Bullet();
}
}
// unique_ptr destructor will take care of deallocating the storage
The above is a pretty simple case. Making non-trivial uses of this method exception safe without wrapping it all up in a class is more difficult. Wrapping it up in a class basically amounts to implementing std::vector.
4) std::vector
So just use std::vector.
It's possible to do what you want -- search for "operator new" if you really want to know how. But it's almost certainly a bad idea. Instead, use std::vector, which will take care of all the annoying details for you. You can use std::vector::reserve to allocate all the memory you'll use ahead of time.
Bullet** pBulletArray = new Bullet*[iBulletArraySize];
Then populate pBulletArray:
for(int i = 0; i < iBulletArraySize; i++)
{
pBulletArray[i] = new Bullet(arg0, arg1);
}
Just don't forget to free the memory using delete afterwards.
The way C++ new normally works is allocating the memory for the class instance and then calling the constructor for that instance. You basically have already allocated the memory for your instances.
You can call only the constructor for the first instance like this:
new((void*)pBulletArray) Bullet(int foo);
Calling the constructor of the second one would look like this (and so on)
new((void*)pBulletArray+1) Bullet(int bar);
if the Bullet constructor takes an int.
If what you're really after here is just fast allocation/deallocation, then you should look into "memory pools." I'd recommend using boost's implementation, rather than trying to roll your own. In particular, you would probably want to use an "object_pool".

Can I specify default value?

Why is it that for user defined types when creating an array of objects every element of this array is initialized with the default constructor, but when I create an array of a built-in type that isn't the case?
And second question: Is it possible to specify default value to be used while initializing elements in the array? Something like this (not valid):
char* p = new char[size]('\0');
And another question in this topic while I'm with arrays. I suppose that when creating an array of user defined type, every element of this array will be initialized with default value. Why is this?
If arrays for built in types do not initialize their elements with their defaults, why do they do it for User Defined Types?
Is there a way to avoid/circumvent this default construction somehow? It seems like bit of a waste if I for example have created an array with size 10000, which forces 10000 default constructor calls, initializing data which I will (later on) overwrite anyway.
I think that behaviour should be consistent, so either every type of array should be initialized or none. And I think that the behaviour for built-in arrays is more appropriate.
That's how built-in types work in C++. In order to initialize them you have to supply an explicit initializer. If you don't, then the object will remain uninitialized. This behavior is in no way specific to arrays. Standalone objects behave in exactly the same way.
One problem here is that when you are creating an array using new[], you options for supplying an initializer (in the current version of the language) are very limited. In fact, the only initializer you can supply is the empty ()
char* p = new char[size]();
// The array is filled with zeroes
In case of char type (or any other scalar type), the () initializer will result in zero-initialization, which is incidentally what you tried to do.
Of course, if your desired default value in not zero, you are out of luck, meaning that you have to explicitly assign the default values to the elements of the new[]-ed array afterwards.
As for disabling the default constructor call for arrays of types with user-defined default constructor... well, there's no way to achieve that with ordinary new[]. However, you can do it by implementing your own array construction process (which is what std::vector does, for one example). You first allocate raw memory for the entire array, and then manually construct the elements one-by-one in any way you see fit. Standard library provides a number of primitive intended to be used specifically for that purpose. That includes std::allocator and functions like uninitialized_copy, uninitialized_fill and so on.
Something like this (not valid):
As far as I know that is perfectly valid.
Well not completely, but you can get a zero intialized character array:
#include <iostream>
#include <cstdlib>
int main(int argc, char* argv[])
{
//The extra parenthesis on the end call the "default constructor"
//of char, which initailizes it with zero.
char * myCharacters = new char[100]();
for(size_t idx = 0; idx != 100; idx++) {
if (!myCharacters[idx])
continue;
std::cout << "Error at " << idx << std::endl;
std::system("pause");
}
delete [] myCharacters;
return 0;
}
This program produces no output.
And another question in this topic while I'm with arrays. I suppose that when creating an array of user defined type and knowing the fact that every elem. of this array will be initialized with default value firstly why?
Because there's no good syntactic way to specialize each element allocated with new. You can avoid this problem by using a vector instead, and calling reserve() in advance. The vector will allocate the memory but the constructors will not be called until you push_back into the vector. You should be using vectors instead of user managed arrays anyway because new'd memory handling is almost always not exception safe.
I think that behaviour should be consistent, so either every type of array should be initialized or none. And I think that the behaviour for built-in arrays is more appropriate.
Well if you can think of a good syntax for this you can write up a proposal for the standard -- not sure how far you'll get with that.
Why is it that for user defined types when creating an array of objects every element of this array is initialized with the default constructor, but when I create an array of a built-in type that isn't the case? and
And another question in this topic while I'm with arrays. I suppose that when creating an array of user defined type, every element of this array will be initialized with default value. Why is this? and
If arrays for built in types do not initialize their elements with their defaults, why do they do it for User Defined Types?
Because a user defined type is never ever valid until its constructor is called. Built in types are always valid even if a constructor has not been called.
And second question: Is it possible to specify default value to be used while initializing elements in the array? Something like this (not valid):
Answered this above.
Is there a way to avoid/circumvent this default construction somehow? It seems like bit of a waste if I for example have created an array with size 10000, which forces 10000 default constructor calls, initializing data which I will (later on) overwrite anyway.
Yes, you can use a vector as I described above.
Currently (unless you're using the new C++0x), C++ will call the constructor that takes no arguments e.g. myClass::myClass(). If you want to initialise it to something, implement a constructor like this that initialises your variables. e.g.
class myChar {
public:
myChar();
char myCharVal;
};
myChar::myChar(): myCharVal('\0') {
}
The C++ philosophy is - don't pay for something you don't need.
And I think the behviour is pretty unified. If your UDT didn't have a default constructor, nothing would be run anyway and the behaviour would be the same as for built-in types (which don't have a default constructor).
Why is it that for user defined types when creating an array of objects every element of this array is initialized with the default constructor, but when I create an array of a built-in type that isn't the case?
But if the default constructor of an object does nothing then it is still not initialiized.
class X
{
public:
char y;
}
X* data = new X[size]; // defaut constructor called. But y is still undefined.
And second question: Is it possible to specify default value to be used while initializing elements in the array? > Something like this (not valid):
Yes:
char data1[size] = { 0 };
std::vector<char> data2(size,0);
char* data3 = new char[size];
memset(data3,0,size);
Is there a way to avoid/circumvent this default construction somehow? It seems like bit of a waste if I for example have created an array with size 10000, which forces 10000 default constructor calls, initializing data which I will (later on) overwrite anyway.
Yes. Use a std::vector.
You can reserve the space for all the elements you need without calling the constructor.
std::vector<char> data4;
data4.reserve(size);