I have a member variable two-dimensional vector in a class, like this:
#include <vector>
...
class MyClass {
private:
int vector_size;
std::vector<std::vector<int> > vector_2d;
public:
MyClass(int _vector_size);
~MyClass();
} // class MyClass
I want to know the best way of implementing the constructor MyClass(int _vector_size) to fully initialize the vector to consist of _vector_size empty vectors. The code I have now is as follows (and this works perfectly fine in a little toy program I wrote to test correctness), but I feel like the declaration of temp_vec and the constant temp_vec.clear() might be a little redundant.
MyClass::MyClass(int _vector_size):
vector_size(_vector_size)
{
// initialize vector_2d
vector_2d.clear();
// push initialized 1D vectors
for (int i = 0; i < vector_size; ++i) {
std::vector<int> temp_vec;
temp_vec.clear();
vector_2d.push_back(temp_vec);
}
}
I have also checked other posts such as this, this, and this, but I think my question differs in that I want a vector of specified size that consists of vectors of unspecified size.
std::vector have a constructor overload which takes a size for the vector.
You can use this to initialize your vector:
MyClass::MyClass(int size)
: vector_size(size),
vector_2d(size)
{
}
This will initialize vector_2d to have size elements. Each element is a default-constructed std::vector<int> object (the type of each element).
In your code, vector_2d is default-initialzied as empty std::vector firstly (thus calling of clear() is superfluous), then gets modified in the body of constructor.
You can initialize it directly in member initializer list. E.g.
// initializa vector_2d as containing _vector_size empty std::vector<int>
MyClass::MyClass(int _vector_size):
vector_size(_vector_size), vector_2d(_vector_size) {}
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
};
The struct
struct Vanish
{
int iCount;
int iRow;
};
I defined a std::vector of Vanish as a member of my class, and want to initialise it in the constructor like this:
class BigClass
{
public:
BigClass();
private:
std::vector<Vanish> tovanish;
};
void BigClass::BigClass()
{
Vanish empty = {0,0};
tovanish.assign(MAX_VANISH, empty);
}
Is there a better way, or is this considered OK?
It is better to do that in the constructor's initializer list:
BigClass::BigClass()
: tovanish(MAX_VANISH)
{
}
That way, you'll avoid possible vector reallocations. Note that you vector's constructor will value-initialize its elements. Value-initialization of the int members in Vanish just zeroes them.
Note that in C++11, using uniform-initialization you could specify other values easily:
BigClass::BigClass()
: tovanish(MAX_VANISH, {42, 24})
{
}
Is there a better way?
Yes, sure,
BigClass::BigClass() : tovanish(MAX_VANISH) {}
This gives you a vector with MAX_VANISH value-initialized Vanish elements.
I have a class field which is a std::vector. I know how many elements I want this vector to contain: N. How do I initialize the vector with N elements?
std::vector has a constructor declared as:
vector(size_type N, const T& x = T());
You can use it to construct the std::vector containing N copies of x. The default value for x is a value initialized T (if T is a class type with a default constructor then value initialization is default construction).
It's straightforward to initialize a std::vector data member using this constructor:
struct S {
std::vector<int> x;
S() : x(15) { }
}
class myclass {
std::vector<whatever> elements;
public:
myclass() : elements(N) {}
};
All the constructors that allow you to specify a size also invoke the element's constructor. If efficiency is paramount, you can use the reserve() member function to reserve the size. This does not actually create any elements, so it is more efficient. In most cases, though, supplying the size through the vector constructor is just fine.
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.