Extending default copy constructor - c++

In a copy constructor of a struct/class, how can I avoid copying all the basic (int, double, etc.) members one by one if the intention is to copy a pointer successfully? Is it possible to extend the default copy constructor in this sense?
struct Type
{
int a;
double b;
bool c;
// ... a lot of basic members
int* p;
Type()
{
p = new int;
*p = 0;
}
Type (const Type& t)
{
// how to avoid copying these members one by one
this.a = t.a;
this.b = t.b;
this.c = t.c;
// but only add this portion
this.p = new int;
*this.p = *t.p;
}
};

Create an RAII wrapper for the int * data member that allows copying/moving.
struct DynInt
{
std::unique_ptr<int> p;
DynInt() : DynInt(0) {}
explicit DynInt(int i) : p(new int(i)) {}
DynInt(DynInt const &other) : p(new int(*other.p)) {}
DynInt& operator=(DynInt const& other)
{
*p = *other.p;
return *this;
}
DynInt(DynInt&&) = default;
DynInt& operator=(DynInt&&) = default;
// maybe define operator* to allow direct access to *p
};
Then declare your class as
struct Type
{
int a;
double b;
bool c;
// ... a lot of basic members
DynInt p;
};
Now, the implicitly generated copy constructor will do the right thing.

Related

Assigment Operator for objects with user defined pointer members

I am trying to implement an operator= in C++ for an object which has as a member a pointer to a user defined type which also has dynamic memory allocated in it.
So given the code below, how would on implement a correct operator= for B? What I am after is how is the dynamic memory in A copied to the new B object?
Any help would be much appreciated.
Thank you
class A
{
int a;
int* b;
public:
A()
{
a = 1;
b = new int [20];
}
};
class B
{
A* a;
public:
B()
{
a = new A;
}
}
For starters you should define at least copy constructor, copy assignment operator and destructor for the class A. Then it is simple to define the copy assignment operator for the class B.
For example
#include <iostream>
#include <algorithm>
class A
{
static const size_t N = 20;
int a;
int* b;
public:
A()
{
a = 1;
b = new int [N]();
}
A( const A &a ) : a( a.a ), b( new int [N] )
{
std::copy( a.b, a.b + N, this->b );
}
A & operator =( const A &a )
{
if ( &a != this )
{
this->a = a.a;
int *p = new int[N];
std::copy( a.b, a.b + N, p );
delete [] this->b;
this->b = p;
}
return *this;
}
~A()
{
delete []b;
}
};
class B
{
A* a;
public:
B() : a( new A )
{
}
// copy constructor
~B()
{
delete a;
}
B & operator =( const B &b )
{
if ( this != &b )
{
*this->a = *b.a;
}
return *this;
}
};
int main()
{
B b1;
B b2;
b1 = b2;
}
Pay attention to that in the copy assignment operator at first created a new array before deleting the old one. This allows to keep the stable state of the assignable object if an exception will occur.
At very first: Have a look at the rule of three, it is an absolute must go in given case. Consider, too, the rule of five, while not mandatory, you'll leave out a great optimisation opportunity...
The destructor would now delete[] the array (leaving this part to you...), a copy constructor would then do exactly that: (deep) copy the data:
A::A(A const& other)
: a(other.a), b(new int[20]) // assuming you have a fixed size for those arrays;
// better: introduce a constant for to avoid magic
// numbers in code!
{
// you created a new array, but yet need to fill it with the others value
std::copy(other.b, other.b + 20, b);
}
OK, first step. Using the copy and swap idiom, the assignment operator gets pretty simple:
A& operator=(A other) // YES, no reference! This will invoke the copy (or move!)
// constructor of your class!
{
swap(*this, other); // you'll need to implement it yet!
return *this;
// at this point, the destructor of other will clean up data that was potentially
// contained in *this before...
}
Finally the move constructor:
A::A(A&& other)
: a(0), b(nullptr)
{
swap(*this, other);
// again swapping??? well, sure, you want the data from other to be contained
// in *this, and we want to leave other in some kind of valid state, which the
// nullptr is fine for (it's fine to delete[] a null pointer, so you don't even
// need to check in the destructor...)
}
And now up to you: class B analogously...
Side note: you get away a bit cheaper by use of a smart pointer (std::unique_ptr), it will allow you to default destructor and move constructor + assignment operator, solely copy constructor and assignment operator need to be implemented explicitly (std::unique_ptr is not copiable...).

How to deal with double (or multiple) copy constructors for class with pointers

There is a class called "X" like this:
class X {
private:
int *ptr;
public:
X() {
ptr = new int[2];
ptr[0] = 0;
ptr[1] = 0;
}
X(int a, int b) {
ptr = new int[2];
ptr[0] = a;
ptr[1] = b;
}
X(const X &val) {
delete[] ptr;
ptr = new int[2];
ptr[0] = val.ptr[0];
ptr[1] = val.ptr[1];
}
X get() {
X ret(ptr[0], ptr[1]);
return ret;
}
};
Suppose that there are variable X that is defined with X v(2, 3).
If we call v.get(), it's okay.
But, if we call v.get().get(), it's not okay. It produces runtime error in delete[] ptr section in copy constructor, which the content is that I am trying to delete the undefined (0xcccccccc) pointer.
One possible option for dealing with this is, that using C++-STL like <array> or <vector>. But I want to implement with pointer.
How to deal with this runtime error, with pointer-based implementation?
The simple answer is that you shouldn't delete[] ptr in the copy constructor, because it is uninitialised. You don't need to delete[] ptr in assignment, either. The only place delete or delete[] should occur is in a destructor.
Tidying up your class, without changing from owning raw pointers
class X {
private:
int *ptr;
public:
X() : X(0, 0) { }
X(int a, int b) : ptr(new int[2]) {
ptr[0] = a;
ptr[1] = b;
}
X(const X &val) : X(val.ptr[0], val.ptr[1]) { }
X& operator=(const X &val)
{
ptr[0] = val.ptr[0];
ptr[1] = val.ptr[1];
return *this;
}
X(X&& val) : ptr(val.ptr) {
val.ptr = nullptr;
}
X& operator=(X&& val) {
std::swap(ptr, val.ptr);
return *this;
}
~X() { delete[] ptr; }
X get() {
return *this;
}
};
As a point of nomenclature, a constructor is only a "copy constructor" if it takes an instance of the class as it's single (non-default) parameter. X::X(int, int) is just a constructor. That means there are at most 4 copy constructors (otherwise they would be ambiguous under overload resolution)
X::X(X &)
X::X(const X &)
X::X(volatile X &)
X::X(const volatile X &)
However defining more than one is a terrible idea, unless you in an obfuscation contest

c++ copy assignment operator for reference object variable

I give the following example to illustrate my question:
class Abc
{
public:
int a;
int b;
int c;
};
class Def
{
public:
const Abc& abc_;
Def(const Abc& abc):abc_(abc) { }
Def& operator = (const Def& obj)
{
// this->abc_(obj.abc_);
// this->abc_ = obj.abc_;
}
};
Here I do not know how to define the copy assignment operator. Do you have any ideas? Thanks.
references cannot be assigned to. You need something that can. A pointer would work, but they're very abusable.
How about std::reference_wrapper?
#include <functional>
class Abc
{
public:
int a;
int b;
int c;
};
class Def
{
public:
std::reference_wrapper<const Abc> abc_;
Def(const Abc& abc):abc_(abc) { }
// rule of zero now supplies copy/moves for us
// use the reference
Abc const& get_abc() const {
return abc_.get();
}
};
A reference cannot be assigned. Due to this, one can only define it via placement new and copy construction:
Def& operator = (const Def& obj)
{
this->~Def(); // destroy
new (this) Def(obj); // copy construct in place
}
But it is really unnecesary. Just use a pointer.

C++11 move constructor for union-like class

Is there a better way to build a move constructor for a union-like class? If I were to have a union-like class like the class in the following code, is there a way to build the class or the move constructor that wouldn't require switch statement like the move constructor in the following code.
class S {
private:
enum {CHAR, INT, DOUBLE} type; // tag
// anonymous union
union {
char c;
int n;
double d;
};
public:
// constructor if the union were to hold a character
AS(const char c) {
this->tag = AS::CHAR;
this->c = c;
}
// constructor if the union were to hold a int
AS(const int i) {
this->tag = AS::INT;
this->n = i;
}
// constructor if the union were to hold a double
AS(const double d) {
this->tag = AS::DOUBLE;
this->d = d;
}
// Move constructor with switch statement
S(S &&src) : type(std::move(src.type)) {
switch(type) {
case CHAR:
this->c = src.c);
src.c = 0;
break;
case INT:
this->n = src.n;
src.n = 0;
break;
case DOUBLE:
this->d = src.d;
src.d = 0
break;
default:
break;
}
}
};
No, there is no better way. If you want to safely move from a union containing arbitrary types, you must do so from the field of the union that has last been written to (if any). The other answer stating the contrary is wrong, consider an example like
union SomethingLikeThisIsGoingToHappenInPractice {
std::string what_we_actually_want_to_move;
char what_we_do_not_care_about[sizeof(std::string)+1];
};
If you use the move constructor of the 'largest' type here you'd have to pick the char array here, despite moving that actually not really doing anything. If the std::string field is set you'd hope to move its internal buffer, which is not going to happen if you look at the char array. Also keep in mind that move semantics is about semantics, not about moving memory. If that was the issue you could just always use memmove and be done with it, no C++11 required.
This isn't even going into the problem of reading from a union member you haven't written to being UB in C++, even for primitive types but especially for class types.
TL;DR if you find yourself in this situation use the solution originally proposed by the OP, not what's in the accepted answer.
PS: Of course if you are just moving a union that only contains things that are trivially moveable, like primitive types, you could just use the default move constructor for unions which does just copy the memory; In that case it's really not worth it to have a move constructor in the first place though, other than for consistencies sake.
Since unions as a data type refer to the same place in memory for all of the fields inside (although the ordering of smaller fields like the 4 bytes of char array[4] within that space depends on the system), it is possible to just move the union using the largest field. This will ensure that you move the entire union every time, regardless of which fields you are currently using the union for.
class S {
private:
enum {CHAR, INT, DOUBLE} type; // tag
// anonymous union
union {
char c;
int n;
double d;
};
public:
// Move constructor with switch statement
S(S &&src) : type(std::move(src.type)) {
this->d = src.d;
src.d = 0;
}
};
Yes, there is better way. At first it have to add EMPTY tag, after this use delegating copy constructor:
class S {
private:
enum {EMPTY, CHAR, INT, DOUBLE} type; // tag
// anonymous union
union {
char c;
int n;
double d;
};
public:
S(){ this->type = EMPTY; }
// constructor if the union were to hold a character
S(const char c) {
this->type = CHAR;
this->c = c;
}
// constructor if the union were to hold a int
S(const int i) {
this->type = INT;
this->n = i;
}
// constructor if the union were to hold a double
S(const double d) {
this->type = DOUBLE;
this->d = d;
}
S(const S& src) = default;// default copy constructor
// Move constructor
S(S&& src)
: S(src) // copy here
{
src.type = EMPTY; // mark src as empty
}
};
Of course, this example is not very useful, unlike the example below, which adds work with a pointer to a string:
#include <cassert>
#include <iostream>
#include <memory>
#include <string>
class S {
public:
enum Tag {EMPTY, CHAR, INT, DOUBLE, STRING};
private:
Tag type;
// anonymous union
union {
char c;
int n;
double d;
std::string* str;
};
public:
S(){ this->type = EMPTY; }
// constructor if the union were to hold a character
S(const char c) {
this->type = CHAR;
this->c = c;
}
// constructor if the union were to hold a int
S(const int i) {
this->type = INT;
this->n = i;
}
// constructor if the union were to hold a double
S(const double d) {
this->type = DOUBLE;
this->d = d;
}
S(std::unique_ptr<std::string> ptr) {
this->type = STRING;
this->str = ptr.release();
}
std::unique_ptr<std::string> ExtractStr()
{
if ( this->type != STRING )
return nullptr;
std::string* ptr = this->str;
this->str = nullptr;
this->type = EMPTY;
return std::unique_ptr<std::string>{ptr};
}
Tag GetType() const
{
return type;
}
private:
// only move is allowed for public
S(const S& src) = default;// default copy constructor
S& operator = (const S& src) = default;// default copy assignment operator
public:
// Move constructor
S(S&& src)
: S(src) // copy here (but we copy only pointer for STRING)
{
src.type = EMPTY; // mark src as empty
}
S& operator = (S&& src)
{
if ( this->type == STRING )
ExtractStr();// this call frees memory
this->operator=(src);
src.type = EMPTY;
return *this;
}
~S()
{
if ( this->type == STRING )
{
ExtractStr();// this call frees memory
}
}
};
// some test
int main()
{
S sN(1);
S sF(2.2);
S x{std::move(sN)};
std::unique_ptr<std::string> pStr1 = std::make_unique<std::string>("specially for Daniel Robertson");
std::unique_ptr<std::string> pStr2 = std::make_unique<std::string>("example ");
std::unique_ptr<std::string> pStr3 = std::make_unique<std::string>("~S() test");
S xStr1(std::move(pStr1));
S xStr2(std::move(pStr2));
S xStr3(std::move(pStr3));
x = std::move(xStr1);
assert(xStr1.GetType() == S::EMPTY);
assert(x.GetType() == S::STRING);
std::string str2 = *xStr2.ExtractStr();
std::cout << str2 << *x.ExtractStr() << std::endl;
return 0;
}

C++ operator syntax for handling a = b + c without making explicit copy of data in "a.data_ptr"

I would like to further exhaust this topic.
Assume that I have something like:
class MyClass
{
public:
MyClass(int N)
{
data_ptr = new float[N];
};
float* dat_ptr;
// ... clever operator definition here ...
};
So I would like to be able to simply write:
MyClass a(4);
MyClass b(4);
MyClass c(4);
// modify b.data_ptr and c.data_ptr ....
// Use "clever operator"
a = b + c;
Where the operator would do a.data_ptr[i] = b.data_ptr[i] + c.data_ptr[i] for i=0:(N-1) ...
Hence no extra copies of the data are created and we are neatly using the preallocated buffers.
Is this possible? If so, please provide me with som insights as to how it would be done.
Thanks!
You can, if you use move semantics from C++11.
class MyClass
{
public:
MyClass(int N)
{
data_ptr = new float[N];
n = N;
}
MyClass(MyClass && rhs)
{
data_ptr = rhs.data_ptr;
n = rhs.n;
rhs.data_ptr = nullptr;
}
// dtor, copy-ctor etc.
int n;
float * dat_ptr;
};
MyClass operator + (const MyClass & left, const MyClass & right)
{
MyClass result(left.n);
// Implement addition
}
// Note: no error-checking
This way a temporary object will be created, but the internal data will not be unnecessarily copied.
Read more about the move semantics.
It is not possible; Before a is assigned to, a temporary object will be created as a result of calling operator + (b, c); This operator should return the created instance, that should then be assigned to a; the created instance is always created by b + c.
What is possible though is to define += as a member operator and say:
b += c;
This would modify the value of b without creating extra copies.
Edit: I have reconsidered :)
You definitely can do it, by abstracting operations as lazy evaluation objects.
Here is an example:
class MyClass; // fwd. declaration of your class
struct LazySum
{
LazySum(const MyClass& a, const MyClass& b)
: x(a), y(b) {}
float operator[](int i) { return x[i] + y[i]; }
const MyClass& x;
const MyClass& y;
};
class MyClass
{
public:
MyClass(int N)
{
data_ptr = new float[n = N];
};
int n; // this shouldn't be public
float* dat_ptr; // nor this, but I went with your code
// ... clever operator definition here ...
MyClass& operator=(const LazySum& terms)
{
// ignore case when n != x.n or n != y.n
// because not the point of the example
// (and I'm lazy)
// sum evaluation occurs here
// with no new allocations
for(int i = 0; i < n; ++i)
data_ptr[i] = terms[i];
return *this;
}
};
LazySum operator=(const MyClass& x, const MyClass& y)
{
return LazySum(x, y); // LazySum is a couple of references in size
}
void client_code_using_clever_op()
{
MyClass a(4);
MyClass b(4);
MyClass c(4);
// modify b.data_ptr and c.data_ptr ....
// Use "clever operator"
a = b + c; // actual sum performed when operator = is executed
}
The idea is to store the terms, and perform late evaluation on the terms.
Points of improvement:
inject a functor in the construction of LazySum to make it become LazyOp (the functor would decide what the op is); Implement other binary operators on MyClass in terms of it.
use RAII in MyClass.
when you need to implement lazy evaluation operators on another type (e.g. some MyOtherClass) consider implementing LazyOp as a template on the terms and functor type.
this does not support more complex expressions without some extra work:
MyClass a(4), b(4), c(4), d(4);
d = (a + b) + c; // error
This example will not work because it would require an operator+(const LazySum&, const MyClass&);;
As Spook explained, yes it is possible. Just for fun I wrote a full example that you can compile and run. If a copy was to be created, you would get a message in the output. I tried this example in Visual Studio 2012 and runs fine.
class MyClass
{
private:
float *data_ptr;
std::size_t size;
public:
MyClass(std::size_t N = 0) :
size(N),
data_ptr(N ? new float[N]() : nullptr)
{}
MyClass(const MyClass& other) :
size(other.size),
data_ptr(other.size ? new float[other.size]() : nullptr)
{
std::copy(other.data_ptr, other.data_ptr + size, data_ptr);
std::cout << "Copy!" << std::endl;
}
MyClass(MyClass&& other)
{
size = 0;
data_ptr = nullptr;
swap(*this, other);
}
~MyClass()
{
delete[] data_ptr;
}
MyClass& operator=(MyClass other)
{
swap(*this, other);
return *this;
}
friend MyClass operator+(MyClass& first, MyClass& second)
{
MyClass result(std::min(first.size, second.size));
for (std::size_t i=0; i < result.size; i++) {
result.data_ptr[i] = first.data_ptr[i] + second.data_ptr[i];
}
return result;
}
friend void swap(MyClass& first, MyClass& second)
{
std::swap(first.size, second.size);
std::swap(first.data_ptr, second.data_ptr);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
MyClass a(5);
MyClass b(5);
MyClass c(5);
a = b + c; //this should not produce an extra copy
return 0;
}