Let's say I have an array of objects declared in my header. The size of the array could be very large. In my source file, I create the constructor for my class and I'd like to initialize all the objects in my array. If these objects are not being constructed with a zero-parameter constructor, I am told these need to be put in my initialization list.
My question is if I want to use a loop to initialize this possibly large array of objects, that wouldn't go in the initialization list, would it? I wouldn't want to put in my initialization list: str1("1"), str2("2"), ... , strn("n"). Could a loop to initialize all these objects go in the header or possibly in the body of the constructor?
Please let me know. I have not seen an example of this.
Thanks,
jbu
You are not able to loop in an initializer list, however there is no issue with looping in the constructor body, so long as the object type has a valid assignment operator. The objects in the array will be first initialized using their zero-parameter constructor, before the constructor body. Then in the body you will re-assign them to whatever they need to be.
Also note that if each object in the array is to be initialized using the same NON-zero parameter constructor, you can use an std::vector type, and in the initializer list, specify the default non-zero constructor to be used when allocating the internal array, ie:
// in .h
class MyClass
{
...
MyClass();
private:
vector<SomeObject> objects;
};
// in .cpp
MyClass::MyClass()
: objects(100,SomeObject(10, "somestring"))
{
}
you'll have to wait for C++0x to initialize an array in the initializer list.
struct S {
int a[3];
S(int x, int y, int z) :a{x,y,z} { /*…*/ }; // solution to old problem
};
It is possible to do like this using boost assign to declare a const vector of elements :
#include<vector>
#include<iostream>
#include<boost/foreach.hpp>
#include<boost/assign.hpp>
#include<boost/assign/list_of.hpp>
#include<boost/assign/std/vector.hpp>
using namespace std;
using namespace boost;
using namespace boost::assign;
typedef vector<int> int_vector;
const int_vector my_const_vector = list_of
(1)(2)(3)(5)(8)(13)(21)(34)(55)(89);
class myClass
{
public :
// initialization list used in the constructor
myClass(const int_vector & vec)
: m_member_vector(int_vector(vec.begin(), vec.end()))
{}
void print() const
{
BOOST_FOREACH(int i, m_member_vector)
{ cout << i << endl; }
}
private :
int_vector m_member_vector;
};
void main()
{
myClass m(my_const_vector);
m.print();
}
You can get boost from here . I realize this isn't arrays but this does solve your problem - in a way
You cannot initialize arrays in an initialization list. You have to do it in the body of the constructor.
If the thing you want to have an array of is not default-constructable, the simplest solution is to use a std::vector instead of a raw array. That way you can construct the elements as you add them within the constructor body.
But if you insist on having as a class member a raw array of objects whose type does not have a default constructor, then your only real option is to make it an array of pointers-to-Foo rather than an array of Foo.
Not a "newbie" answer, nor one I would use, but you can have a look at the boost preprocessor library, which allows you to create loops with the preprocessor.
From your question it looks like you'd like to initialize each element of the array with a different parameter (as implied by the list str1("1"), str2("2"), strn("n")). This is not possible with the current C++; And as TimW noted C++0X will allow support for this type of initialization via sequence constructors.
Having said that, it seems what you want to do is run-time initialization of these values ("1"), ("2")...("n") (Do you know these values at compile time?). If that's the case, I don't think you can use an initialization list even in C++0X. If that's not the case(compile time parameter passing for this very large array), then the preprocessor magic is the way to go.
Related
I want to have a stack-allocated array initialized by a copy constructor.
I only see methods allocating memory on the heap, or using std::array.
With std::array, it would look like the following:
class A
{
std::array<int, 5> my_array; // I would like to have int my_array[5]; instead of the std::array
int size;
public:
A(const A& p)
: my_array{ p.my_array }, size(p.size) {}
}
How can I implement this without std::array<int,5> but with a plain array (int my_array[5];)? I have added this in the comment in the code.
At the moment, the array contains integers. If this would contain, let's say a class B, which contains also a pointer:
class B
{
int* my_ptr;
}
Does std::array handle this correctly and perform a deep copy?
Arrays cannot be copy-initialised in C++. You can either:
Assign each member in a loop i.e. std::copy in the constructor body.
Or wrap the array inside a class, and use the generated copy constructor. There is a template for such wrapper class in the standard library. It's the std::array that you already know of.
Of course, your class itself is a class that is a wrapper for the array, so you could simply not have user defined copy constructor, and instead use the implicitly generated one:
struct A
{
int my_array[5];
int size;
};
If this would contain, let's say a class B which contains also a pointer ... does the std::array handle this correctly
Yes.
... and performs a deep copy?
No. Copying a std::array copies each element and nothing more. Copying a pointer is a shallow copy.
i want to use values that I declare in the constructor with passed variables in the Header file. Is that somehow possible? In my case I give the constructor two int values with these values I want to set the size of a array. Was there a way to do that in the header file? Like this:
class test
{
public:
test(int valueA); //Constructor
float testArray [valueA]; //Array
}
No you can't do it like this and no, that's not even legal C++. The size of an array must be known at compile time. You should use std::vector<float> instead and initialize it in the constructors initializer list:
#include <vector>
class test
{
public:
test(int valueA) : testArray(valueA) {}
std::vector<float> testArray;
}
This will initialize testArray with valueA values.
As written: no.
Two options:
Use a class that doesn't need it's size set (like std::vector). This is the better approach.
Or dynamically create the array once you do know the size. This isn't a great approach, but may be closer to the intent of the original question. As pointed out in the comments to avoid dynamic memory issues, since there is a destructor you probably want a copy constructor and a copy assignment constructor to ensure you don't end up with two text classes sharing the same array.
class test
{
public:
test(int valA)
{
testArray = new float[valA];
}
~test()
{
delete[] testArray;
}
private:
float* testArray
};
Suppose I have a C++ class set up as follows:
class Foo{
public:
struct Pair{
int x;
int y;
Pair(){ x = 2; y = 4; }
};
private:
Pair pairArr[16];
}
Without otherwise initializing the pairArr, what is the default value of the Pair structs inside it? Does C++ call the constructor (initializing it with x=2, y=4) or are the objects not created yet, leaving me with an array of "junk" objects until I initialize the indices myself?
I know if it is an array of a primitive data type, they are default initialized (if I had an array of ints, they would all be 0). However, I don't know if this behavior holds for more complex objects like my struct here.
Classes and structs are equivalent in c++, it's only the default access specifier that differs. So check Arrays and Classes, which says:
The normal array declaration style uses the default constructor for each object in the array (if the class has a default constructor)
From a practical point of view, do this in your struct:
Pair() : x(2), y(4) { std::cout << "Called\n"; }
and you will see the message being printed 16 times.
That's a usual approach (to add print messages to constructor to destructor) when you want to know what is called (and usually their order).
Tip: Use an initializer list, rather than assigning values inside the body of the constructor.
I'm self studying C++.
If you're making a Class which only has a member variable that is a collection of "X" objects, (whatever X may be) would having just a default constructor and a deconstructor be enough seems its purely dealing with a collection of objects? Thanks.
EDIT: Sorry should have been clearer. For a different example, if you have a class "Aclass" that has an int, a string and a vector of objects of another class, would you advise the "Aclass" class to have a constructor with parameters? ie Aclass(int i, string s); and do you need to have the vector in the constructor too? I'm a little confused. Thanks.
If by "collection of 'x' objects" you mean "a standard container of 'x' objects", and by "enough" you mean "enough not to worry about resource management" then yes. Same goes for any well-written container made by you or a third-party.
This is also assuming your X objects are handling their resources correctly. And that they have semantics that are compatible with the container you're putting them in.
Edit
You don't need a constructor like that if you are OK having an object filled with default values for everything. I.e. empty containers, zeroed members (or was it uninitialized? -_-), etc.
You only really need a custom constructor if your object will be in an invalid state without one or if you want some sort of custom logic to run.
You mean enough to handle memory correctly? Depends on the type X. For example, if you have a vector<string> data member, you don't have to do any manual memory management in your class.
For class you may write your own constructor, which shows, how to construct inner objects, i.e
class A{
string s;
int x;
A(string t):s(t), x(17){} // x is always 17 after construction
}
But if inner object is default-constructable, you may leave it's construction and it will be costruct by default.
A(int l):x(l){}
is equivalent to
A(int l):x(l), s(){}
(except for primitive types), that may contain trash by default
If you use default constructor of A, all inner objects will construct by default.
If by collection you mean standard library classes, you would need copy ctor and assignment operator= overloaded.
std::map and std::set would reqire an additional comparison operator< overloaded.
std::unorderd_map and std::unordered_set would need a std::hash specialized for your type.
Often you don't have to define a default constructor. The compiler will declare a default constructor implicitly if one is needed and no constructors are defined. Often it will be useful to define additional constructors (like the one you mention) in addition to the default one. In that case you need to define both:
class A
{
public:
string s;
int x;
// default constructor, no arguments
A(): x(), s() {}
// constructor
A(int i, string t): x(i), s(t) {}
}
int main()
{
A a1;
A a2(5, "text");
vector<A> ls;
return 0;
}
As pwned mentions, in order to use your class A in an STL container, e.g. vector, it is required that A has a default constructor as in the example (either user-defined or implicit).
I want to create an default constructor for my object A. My problem is that one of A object`s variables is a vector array B objects.
Basically the line giving my trouble currently looks like this:
A(): name(""), bArray({B()}), n(0) {}
It must be some syntax issue.
Full constructor looks like that:
A(string n, vector<B> in, int k): name(n), bArray(in), n(k) {}
You don't need to initialize the vector in the initializer list. Member classes are already constructed using the default constructor, which, in your case, will initialize your vector to an empty one.
Since n and in will have their own default constructors, you don't need to explicitly initialize them. Just initialize k to 0, omit the other two and you should be fine.