Initializing array on stack with copy constructor - c++

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.

Related

Is there any way to use parameters from the constructor in a c++ header Flie

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
};

private member array initialization through constructor initializer's list in c++

After going through all the questions asked about aggregate member initialization through initializer list still i am left with the question mark??? i have tried these two methods to initialize the private member array.
class C {
C(const vector<int> &a): m_array(a) {} // using vector
private:
C(initializer_list<int> a): m_array(a) {} //using initializer list
int m_array[6];
};
both of the above methods throw error "cannot specify explicit initializer for arrays" in visual studio 2010. can somebody explain that whether these ways are correct, if yes then why these errors are coming up...
Both these constructions require that arrays would have constructors with one parameter of type either std::vector<int> or std::initializer_list<int>. However arrays are aggregates. They have no constructor with parameter.
You should initialize the array in the bodies of the constructors.
One of approaches is to declare pointer to the first element of an array as the parameter and inside the body of the constructor to copy elements in the data member array.
For example
C( const int *a, size_t n )
{
std::copy_n( a, std::min<size_t>( n, 6 ), array );
}
The other way is to use standard class std::array. For example
std::array<int, 6> array;
C( std::array<int, 6> ): array(a) {}
In the last case the constructor can be called as
C( { 1, 2, 3, 4, 5, 6 } );
.
When you say m_array(a). For this to be valid, m_array should be an object of some class say ArrayClass, which should have a parametrized constructor that accepts argument as you specified.
Now in your case, the m_array represents pointer to first element of the array m_array[]. Its quite simple to say that the constructors are called for objects and not for pointers. Writing m_array(a) means you want to do m_array = a, which is fundamentally wrong as array is allocated on stack and its base address can not be modified and you are trying to modify the array's base address.
What you can do is
take a vector as member and that vector's constructor will take care
of copying the elements.
write your own array class.
use a pointer (shallow copy)

Are C++ arrays copy constructible?

Is this code valid in C++?
class MyClass
{
public:
Class2 array [100];
Myclass (const Myclass& other) : array (other.array) {}
};
If it isn't, what's the best way to achieve the same result?
In C++ arrays are not explicitly copyable (not copy-constructible, not assignable). Your code will not compile.
Yet in C++ arrays become indirectly copyable when wrapped into a class. This means that if you remove your constructor definition, then the implicit copy constructor generated by the compiler for your class MyClass will actually successfully copy the array by some "magical" means that are not available to you directly.
But if for some reason you have to define the copy constructor explicitly, then your options are restricted to leaving the array default-initialized and then explicitly copying the data in the body of the constructor through std::copy or something similar. Or you can simply re-wrap your array, which is actually what the already suggested std::array can do for you.
Regardless of whether or not this is valid, if all your copy constructor does is to copy the array, then I would rather avoid writing it and let the compiler generate one implicitly.
Also, I would recommend following chris's advice in C++11 and use std::array rather than C-style arrays:
#include <array>
class MyClass
{
public: // In case you really want this to be public
std::array<Class2, 100> arr;
};
By the way, this would also allow you to initialize you array in the copy constructor's initializer list (but again, do this only if needed):
class MyClass
{
public:
MyClass() { }
MyClass (const MyClass& other) : arr(other.arr) {}
// ^^^^^^^^^^^^^^
private:
std::array<Class2, 100> arr;
};
Here is a live example.

Initializing a std::vector with default constructor

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.

newbie: C++ question about initialization lists

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.