Are C++ arrays copy constructible? - c++

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.

Related

Initializing array on stack with copy constructor

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.

Is there a way in C++ to deep copy only required variables in CCTOR? [duplicate]

I have a long class with a lot of data members. I want to write a copy constructor for it. But, if I write my own copy constructor, I lose access to the default copy constructor.
I just want to repair a few pointers in my own copy constructor. So I want to have a shallow copy of the object which can be done by the default copy constructor.
Is there a possibility to access the default copy constructor when I have my own copy constructor?
Wrap the things you don't want to change in a struct, and derive (privately) from it. In your copy constructor, simply invoke the copy constructor of your base class.
No you cannot have both default and your own copy c-tor.
But there are two workarounds with this problem:
1 Enclose your pointers in some class with defined copy semantics
Example:
class A {
public:
private:
int trivial1;
int trivial2;
...
SomePointer nontrivialMember;
};
class SomePointer {
public:
SomePointer(const SomePointer&); // here the non trivial part of A copy semantics
int* nonTrivialMember;
};
2 Enclose the trivial parameters in some trivial structure
Example:
class A {
public:
A(const A& o) : data(o.data) {
// non trivial part
}
private:
struct Data {
int trivial1;
int trivial2;
...
} data;
int* nontrivialMember;
};
I would always select the first solution.
[UPDATE]
There is also 3rd solution, very similar to my second, enclose your trivial part in privately inherited base class. I'd still prefer the 1st solution.
The simplest approach to this would be to wrap up the pointers into classes that will perform the 'repair' manually in their copy constructor, then you can happily use the default copy constructor.
No, there is no way to call the default copy constructor from an user defined copy constructor.
You can either use the default or your own, not both. If you want to choose different functionality for different objects you should just write a member function that handles that case.
void DeepCopy(MyClass* rhs);
For example.
You cannot access default copy ctor if you created your own - compiler just doesn't generate it. But ther is workaround - split you class into data structure and logic.
See example:
struct Data
{
int i;
std::string s;
Data(): i(), s() {}
};
class Code: private Data
{
public:
Code() {}
Code(const Code& rhs): Data(rhs) // Call default copy ctor
{
i = 42; // Your copy part
return *this;
}
};
My solution is a simple memcpy() instead of the impossible call to the implicit (compiler generated) copy constructor, as the example shown below:
Class Foo
{
public:
...
Foo (Foo & other) {
// copies trivial part (and non-trivial part with possible wrong values)
memcpy(this, &other, sizeof(Foo));
// your non-trivial part here, overwrites the wrong values (if any) above.
}
}
Yet the side-effect is that the memcpy() will also copy those non-trivial part, which is a waste. If the non-trivial part does not contain too much space, I will prefer my solution.
For example, a class like below wastes only 4 byte copy of the one pointer, assuming the size of a pointer is 4 bytes.
Class Bar
{
int x, y, z;
// memcpy() wastes these 4 bytes copy,
// since actual copy constructor wants a new string
string *s;
}
This worked for me... (C++11, don't know if it works on older std)
Not sure why it doesn't end up in an endless loop.
class Foo {
public:
Foo(const Foo &orig) {
*this = orig;
... exchange pointers, do own stuff
}

Error while declaring a class with std::vector of structs containing std::unique_ptr

Although having worked several years with C#, getting things done in C++ is sometime still difficult for me. I fully embrace the usage of smart pointers, but now I'm facing the following puzzle
I have a struct Foo, e.g.
struct Foo
{
Foo(std::unique_ptr<Bar> bar) : m_myBar(std::move(bar)) {}
private:
std::unique_ptr<Bar> m_myBar;
};
In a different class, I want to have a vector containing instances of Foo, but the following line
std::vector<Foo> m_Foos;
yields compile errors saying that the copy constructor is deleted. In the SO thread "Why can I not push_back a unique_ptr into a vector?" an explanation as well as a remedy is given. However, there the question concerns a vector of unique pointers whereas I have a vector of structs containing a unique pointer. The suggested solution is to use move semantics, but how does that apply in my situation? Or should I be doing something else?
As you say, m_Foos is actually a data member of another class (I'll call it FooHolder). If you didn't provide a copy constructor for FooHolder, the compiler will generate one automatically. That copy constructor will call the copy constructors of all data members of FooHolder, including m_Foos. Of course, the copy constructor of std::vector<Foo> contains a compilation error, since Foo is not copyable. This is probably why you're getting the error.
You'll have to provide an appropriate copy constructor for FooHolder, if you are able to and want that class to be copyable. Otherwise, you can just declare a move constructor (possibly defaulted), which will make the copy constructor deleted:
struct FooHolder
{
FooHolder(FooHolder&&) = default;
private:
std::vector<Foo> m_Foos;
};
You cannot copy unique pointers. You can only move them:
Foo(std::unique_ptr<Bar> bar) : m_myBar(std::move(bar)) {}
// ^^^^^^^^^^^^^^

Can I use a `unique_ptr` in a vector, or do I need to switch to `shared_ptr`?

Given this class with a unique_ptr:
class MyClass
{
public:
MyClass(){}
MyClass(MyClass &&other) : ptr(std::move(other.ptr)){}
std::unique_ptr <int> ptr;
};
Is there any way to make it possible to have a std::vector<MyClass>?
void ThisBreaksIt()
{
MyClass instance;
std::vector<MyClass> mv;
mv.push_back(instance);
}
As-is, this gives me the error
error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>'
This makes sense, since I have no copy constrctor, and when the compiler tries creating a default copy constructor, it tries copying the unique_ptr, which isn't allowed.
I can make it compile by adding this constructor:
MyClass(const MyClass&){}
But of course, this leaves the unique_ptr uninitialized, and is not what I want.
I can't add
MyClass(const MyClass& other) : ptr(std::move(other.ptr)){}
because it's const, and I cant call std::move() on a const object. I can create the constructor
MyClass(MyClass& other) : ptr(std::move(other.ptr)){}
but doesn't solve the original compile error, as vector::push_back uses a const copy constructor.
So, I'm stuck. Is there a way to do what I'm trying to do?
All of these issues go away if I just use a shared_ptr instead of unique_ptr. Is that what I should be doing?
There's no problem storing a non-copyable type in a vector; it's only required to be movable, as yours is.
The problem is that this:
mv.push_back(instance);
tries to insert a copy of instance, and the class is not copyable. But it is movable:
mv.push_back(std::move(instance));
Note that there's no need to write your own default and move constructors in this example. The implicit ones will do the exactly what yours do.
You can use emplace_back. This only allows adding rvalues.
Therefore do this:
void ThisShouldFixIt()
{
mv.emplace_back(MyClass());
}
Note that emplace_back can call the applicable constructor
of T implace, as mentioned below. For what you are doing
push_back is fine though, given that a version taking an rvalue
reference does exist.

Array declaration, size definition, and destruction in c++

So I'm unsure as to what the correct way is to do this. I have a class named someClass, with a private variable that is an array of integers. The size doesn't get defined until the constructor is called. Here's how I do it:
In someClass.h:
class someClass {
public:
someClass();
someClass(int size);
~someClass();
private:
int* array;
}
In someClass.cpp:
someClass::someClass() {
array = new int[9];
}
someClass::someClass(int range) {
array = new int[range];
}
someClass::~someClass() {
delete[] array;
}
Did I declare/define the array correctly? Would it have been much better to use a vector?
Is the destructor correct?
Yes, you're doing it correctly (partially), and yes, it would be better to use a std::vector (because of the "partially" part).
The "partially" is that now you will have to provide a copy constructor and copy assignment operator for your class (and for efficiency, you might want to have a move constructor and move assignment operator as well); if you don't, you'll get double deletion errors if you ever copy the class.
std::vector encapsulates all this, so this is why you should prefer it. Not to mention that it has nice features like iterators.
Your class would then look like this:
class someClass {
public:
someClass();
someClass(int size);
//no destructor necessary!
private:
std::vector<int> array;
}
someClass::someClass()
{} // nothing special needed
someClass::someClass(int range) : array(range)
{}
You should also add copy ctor and copy assignment operator. Remember the rule of three!