fixing shallow copy with a copy constructor - c++

I defined a copy constructor to avoid having a shallow copy of the data member n, but it is not working, v2 is still getting changed when I change v1, what I am doing wrong?
#include<iostream>
using namespace std;
class Vector
{
public:
int *n;
Vector();
Vector(const Vector& vector );
};
Vector::Vector()
{
cout<<"Constructor called"<<endl;
}
Vector::Vector(const Vector& vector )
{
n=new int;
n=vector.n;
cout<<"Copy constructor called"<<endl;
}
int main()
{
Vector v1;
int x=5;
v1.n=&x;
Vector v2=v1;
cout <<"Vector v1 has n value: "<<*v1.n<<endl;
cout <<"Vector v2 has n value: "<<*v2.n<<endl;
*v1.n=499;
cout <<"Vector v1 has n value: "<<*v1.n<<endl;
cout <<"Vector v2 has n value: "<<*v2.n<<endl;
return 0;
}

The problem is that your copy constructor is implemented wrong. You try to fix the shallow copy issue, but your code includes a statement that re-introduces the same issue again.
On this line:
n=new int;
You correctly allocate a new int, which is fine.
But on this line:
n=vector.n;
You are throwing away the int you just allocated, and instead point n to the same int that the other vector's n points to. This is the shallow copy issue all over again.
To fix the issue properly, you need to copy the value of the other vector's n member into your newly allocated n member, eg:
n = new int;
*n = *(vector.n);
Or:
n = new int( *(vector.n) );
That being said, to fully comply with the "Rule of 3", you also need to add a destructor to free n (which means you can't make v1 point to a local int variable in main()), as well as add a copy assignment operator to copy the value of n (similar to the copy constructor). In C++11, you can optionally also comply with the "Rule of 5" by adding a move constructor and move assignment operator, as well.
Try this instead:
#include <iostream>
#include <utility>
//using namespace std; // <-- bad practice!
class Vector
{
private:
int *m_n;
public:
Vector(int x = 0);
Vector(const Vector &src);
Vector(Vector &&src);
~Vector();
Vector& operator=(const Vector &src);
Vector& operator=(Vector &&src);
// alternatively, both operators can be merged into one:
// Vector& operator=(Vector src);
// you should not give outside code directly access to the int* itself,
// that would promote bad practices, and potentially crash your class's
// internal code if outside code assigns a bad pointer.
//
// these accessors provide safer use of the *value* that the int* points
// at, let the class itself be the sole handler of the int* itself ...
int n() const;
void n(int x);
};
Vector::Vector(int x)
: m_n( new int(x) )
{
std::cout << "Converting Constructor called" << std::endl;
}
Vector::Vector(const Vector &src)
: m_n( new int(src.n()) )
{
std::cout << "Copy constructor called" << std::endl;
}
Vector::Vector(Vector &&src)
: m_n( src.m_n )
{
src.m_n = nullptr;
std::cout << "Move constructor called" << std::endl;
}
Vector::~Vector()
{
delete m_n;
std::cout << "Destructor called" << std::endl;
}
Vector& Vector::operator=(const Vector &src)
{
if (&src != this) {
*m_n = src.n();
}
std::cout << "Copy assignment called" << std::endl;
return *this;
}
Vector& Vector::operator=(Vector &&src)
{
Vector tmp(std::move(src));
std::swap(m_n, tmp.m_n);
std::cout << "Move assignment called" << std::endl;
return *this;
}
/* alternatively:
Vector& Vector::operator=(Vector src)
{
std::swap(m_n, src.m_n);
std::cout << "Assignment called" << std::endl;
return *this;
}
*/
int Vector::n() const
{
return *m_n;
}
void Vector::n(int x)
{
*m_n = x;
}
int main()
{
Vector v1(5);
Vector v2 = v1;
std::cout << "Vector v1 has n value: "<< v1.n() << std::endl;
std::cout << "Vector v2 has n value: "<< v2.n() << std::endl;
v1.n(499);
std::cout << "Vector v1 has n value: " << v1.n() << std::endl;
std::cout << "Vector v2 has n value: "<< v2.n() << std::endl;
return 0;
}

Related

Avoid copy construction by std::transform

I'm calling std::transform with a lambda that takes by reference and gives back a reference to the vector element. However, according to my program output, the copy constructor is called and the objects are NOT the same.
Code:
#include <algorithm>
#include <iostream>
#include <vector>
class Math
{
private:
int val_ = 5;
public:
Math(const Math& m) {
std::cout << "Copy constructor, our address: " << this << ", his address: " << &m << std::endl;
}
Math(int val) : val_(val) {
std::cout << "Object constructed with " << val << std::endl;
}
};
int main()
{
std::vector<Math> v_math = { { 5 }, { 10 } };
std::transform(
begin(v_math),
end(v_math),
begin(v_math),
[](const Math& m)-> const Math& {
return m;
});
}
Output (Godbolt):
Object constructed with 5
Object constructed with 10
Copy constructor, our address: 0x23d7ec0, his address: 0x7fff9dc499a8
Copy constructor, our address: 0x23d7ec4, his address: 0x7fff9dc499ac
So three things are unclear to me right now:
Why are the objects different? Shouldn't they be the same?
Why is one object's address bigger than the other? Is this because the copied-to object remains on the stack which has offset-pointers?
How can I avoid copy construction as well (actually I just "misuse" std::transform for a declarative way of invoking a lambda on every std::vector element)?
The copies have nothing to do with your usage of std::transform. They happen when you construct your v_math std::vector, because you're using a std::initializer_list constructor, which forces copies during construction.
In your std::transform call, operator=(const Math&) is called, change your code to the following to see this.
class Math
{
private:
int val_ = 5;
public:
Math(const Math& m) {
std::cout << "Copy constructor, our address: " << this << ", his address: " << &m << std::endl;
}
Math(int val) : val_(val) {
std::cout << "Object constructed with " << val << std::endl;
}
Math& operator=(const Math& other) {
val_ = other.val_;
std::cout << "Operator=(const Math&) called!\n";
return *this;
}
};
int main()
{
std::vector<Math> v_math = { { 5 }, { 10 } };
std::cout << "After constructing v_math!\n";
std::transform(
begin(v_math),
end(v_math),
begin(v_math),
[](const Math& m)-> const Math& {
return m;
});
std::cout << "After std::transform call!\n";
}

Why does the copy constructor and copy assignment operator call `memcpy` whereas the movement ctor and movement assignment operator call `memmove`

As the subject, the related code is listed below.You could check it on https://godbolt.org/z/mAbmwJ.
I completely understand the differences between memcpy(3) and memmove(3), but I don't understand the reasons lie behind it.The code is quoted from an wellknown open source project, I don't doublt the correctness of the code and the developers must have some reasons to do so.
I would be grateful to have some help with this question.
#include<string.h>
#include<iostream>
#define ENTITYID_UNKNOWN 0x00000000
#define ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER 0x000003c2
#define ENTITYID_SEDP_BUILTIN_PUBLICATIONS_READER 0x000003c1
struct EntityId_t
{
static constexpr unsigned int size = 4;
char value[size];
//! Default constructor. Uknown entity.
EntityId_t(){
*this = ENTITYID_UNKNOWN;
}
EntityId_t(int id)
{
int* aux = (int*)(value);
*aux = id;
std::cout << "EntityId_t(int id) constructor" << std::endl;
}
/*!
* #brief Copy constructor
*/
EntityId_t(
const EntityId_t& id)
{
memcpy(value, id.value, size);
std::cout << "copy constructor" << std::endl;
}
EntityId_t& operator =(
const EntityId_t& id)
{
memcpy(value, id.value, size);
std::cout << "copy operator() constructor" << std::endl;
return *this;
}
/*!
* #brief Move constructor
*/
EntityId_t(
EntityId_t&& id)
{
memmove(value, id.value, size);
std::cout << "move constructor" << std::endl;
}
EntityId_t& operator =(
EntityId_t&& id)
{
memmove(value, id.value, size);
std::cout << "move operator(EntityId_t&&)" << std::endl;
return *this;
}
};
int main()
{
EntityId_t c_SEDPPubWriter = ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER;
std::cout << "==============================" << std::endl;
EntityId_t c_SEDSubscribe;
c_SEDSubscribe = ENTITYID_SEDP_BUILTIN_PUBLICATIONS_READER;
}
Output:
EntityId_t(int id) constructor
==============================
EntityId_t(int id) constructor
move operator(EntityId_t&&)
EntityId_t(int id) constructor
move operator(EntityId_t&&)

C++ copy c'tor does now take action. not clear why [duplicate]

This question already has answers here:
What's the difference between assignment operator and copy constructor?
(8 answers)
Closed 4 years ago.
I have this code:
the output of the code is:
cons intcons op+ intcons ;
copycons op+ intcons op+= ;
get_val 3
class declaration::
#include<iostream>
using namespace std;
class Int {
public:
// constructors
Int() : val_(0) { cout << "cons "; }
Int(int n) { val_ = n; cout << "intcons "; }
Int(const Int &v) : val_(v.val_) { cout << "copycons "; }
Int(Int &&v_) { val_ = v_.val_; cout << "mov ctor " ; };
// operations
int get_val() {
cout << "get_val "; return val_;
}
Int operator+(const Int &v) {
cout << "op+ ";
return Int(val_ + v.val_);
}
Int & operator=(const Int &v) {
cout << "op= ";
if (this != &v) {
val_ = v.val_;
}
return *this;
}
Int & operator+=(const Int &v) {
cout << "op+= ";
val_ += v.val_;
return *this;
}
private:
int val_; // value stored in this Int
};
and this is main:
int main(){
Int zero;
Int one = zero + 1;
cout << ";\n";
Int two = zero;
two += one + one;
cout << ";\n";
cout << two.get_val() + 1; cout << endl;
return 0;
}
I was looking at the codes output, and I could agree with each operation that happens and with every output. but one thing isn't clear to me at all. I wonder, why in the first line of the output there isn't use with the copy c'tor?
at first I though maybe it is a move c'tor.
then I built one and it doesn't seemed like the compiler was using it.
can anyone please tell me what is going on? thank you!
I think you are confusing the assignment operator with the copy constructor.
Int two = zero; will cause the copy constructor to be called.
two = zero or two = 1 will cause the assignment operator to be called.
https://techdifferences.com/difference-between-copy-constructor-and-assignment-operator.html

Parameter forwarding without temporary instances

I have a templated class which wraps a std::vector called mObjects.
Class has an insert function which forwards parameters of the actually stored type in the MyArray instance (its called variadic template arguments I think). In this example, I store MyMesh type, but it can be any kind of type.
As you can see in the main() function, mObjects vector doesn't grow, its elements get overwritten over and over again.
Think about an object-pool kind of data structure.
Everything works as expected.
template <class T>
class MyArray
{
public:
MyArray(const int capacity) :
mObjects(capacity)
{
mNextIndex = 0;
}
template <typename... Args>
void insert(Args&&... args)
{
mObjects[mNextIndex] = T{ std::forward<Args>(args)... }; //PROBLEMATIC ASSIGNMENT
//... not relevant code
}
private:
int mNextIndex;
std::vector<T> mObjects;
};
int main()
{
MyArray<Mesh> sa(2);
sa.insert("foo",1111); //goes to mObjects[0]
sa.insert("bar",2222); //goes to mObjects[1], and tada, the vector is full
sa.remove(1111); //not implemented above, but not relevant. Remove func basically adjusts mNextIndex, so mObjects[0] will be overwritten upon next insert.
sa.insert("xxx",3333); //mObjects[0] gets overwritten from "foo" to "xxx" and 1111 to 3333
}
My problem is with one row above commented as //PROBLEMATIC ASSIGNMENT.
mObjects[mNextIndex] = T{ std::forward<Args>(args)... };
When that command executes 3 things happen:
MyMesh(const string s, int x) constructor is called, meaning an entire MyMesh gets allocated on stack here. Why? I just want to pass the forwarded arguments to an existing mObjects[mNextIndex] element.
operator=(MyMesh&& other) is called, and does assignment variable by variable between the temporary variable and mObjects[mNextIndex].
~cVMesh() is called meaning the temporary variable deallocates and dies.
I would like to get rid of #1 and #3. So don't want the "expensive" temporary object creation. I just wish to forward/assign the incoming MyMesh parameters to mObjects[mNextIndex]. Similarly like what std::vector.emplace_back() does, but to any location pointed by mNextIndex.
How can I forward only the parameters to an existing variable in C++, without instantiate temporary variables?
For completness, here is the MyMesh class which gets stored in the MyArray class. Nothing special just printing out some message, when constructor/destructor/assignement operator is called:
class Mesh
{
public:
Mesh()
{
cout << "Mesh()" << std::endl;
mStr = "";
mId = 99999999;
}
Mesh(const string s, int x)
{
cout << "Mesh(const string s, int x)" << std::endl;
mStr = s;
mId = x;
}
~Mesh()
{
cout << "~Mesh()" << std::endl;
}
Mesh& operator=(const Mesh& other)
{
cout << "operator=(const Mesh& other)" << std::endl;
cout << mStr << " becomes " << other.mStr << endl;
cout << mId << " becomes " << other.mId << endl;
mStr = other.mStr;
mId = other.mId;
return *this;
}
Mesh& operator=(Mesh&& other) noexcept
{
cout << "operator=(Mesh&& other)" << std::endl;
cout << mStr << " becomes " << other.mStr << endl;
cout << mId << " becomes " << other.mId << endl;
mStr = other.mStr;
mId = other.mId;
return *this;
}
Mesh(const Mesh& other)
{
cout << "Mesh(const Mesh& other)" << std::endl;
mStr = other.mStr;
mId= other.mId;
}
Mesh(Mesh&& other) noexcept
{
cout << "Mesh(Mesh&& other)" << std::endl;
mStr = other.mStr;
mId = other.mId;
other.mStr = "";
other.mId = 99999999;
}
string mStr;
int mId;
};
I think what you want is to reconstruct an arbitary element in the vector with new values
#include<vector>
template<class T, class... Args>
void create_at_nth_place(std::vector<T>& v, int n, Args&&...args){
auto& elem = v[n];
elem.~T();
new(&elem) T(std::forward<Args>(args)...);
}
struct S {
S();
S(int, bool);
template<class... Args>
S(Args&&...);
S(S&&) noexcept;
~S();
};
void f() {
std::vector<S> v(3);
create_at_nth_place(v, 2, 4323, false);
char a = 'a';
create_at_nth_place(v, 2, 'a', 123, 1232, 32.f, a);
}
Link: https://godbolt.org/g/3K9akZ
mObjects[mNextIndex] = T{ std::forward<Args>(args)... }; line creates a temporary object, performs a move(copy) assignment to object already stored in vector at specified position and finally destroys a temporary.
The whole MyArray class is rather useless since vector already has similar functionality.
vector<Mesh> sa;
sa.reserve(2);
sa.emplace_back("foo",1111); // Mesh constructor called once
sa.emplace_back("bar",2222); // Mesh constructor called once again
You might add:
void assign(const string& s, int x)
{
cout << "assign(const string s, int x)" << std::endl;
mStr = s;
mId = x;
}
And use it:
mObjects[mNextIndex].assign(std::forward<Args>(args)...);
If your mesh class is very heavy, you should consider having an array of pointers, this would eliminate spurious copies altogether. Wouldn't MyArray<std::shared_ptr<MyMesh>> work as is?

Why the destructors are called twice for this functor?

When I run the following program, the destructor is called twice and I'm trying to understand why?
#include <iostream>
#include <vector>
#include <algorithm>
class sample
{
public:
sample() { std::cout << "Constructor " << std::endl; }
~sample() { std::cout << "Destructor" << std::endl; }
void operator()(int i)
{
std::cout << i << " , " << std::endl;
}
};
int main()
{
std::vector<int> iNumbers;
for ( int i = 0 ; i < 5 ; ++i)
iNumbers.push_back(i);
std::for_each(iNumbers.begin() , iNumbers.end() , sample() );
}
The output is as folllows
Constructor
0 ,
1 ,
2 ,
3 ,
4 ,
Destructor
Destructor
Classic rule of three violation. Try this:
#include <iostream>
#include <vector>
#include <algorithm>
class sample
{
public:
sample() { std::cout << "Constructor " << std::endl; }
sample(const sample&) { std::cout << "Constructor (copy)" << std::endl; }
~sample() { std::cout << "Destructor" << std::endl; }
sample& operator=(const sample&) { return *this; }
void operator()(int i)
{
std::cout << i << " , " << std::endl;
}
};
int main()
{
std::vector<int> iNumbers;
for ( int i = 0 ; i < 5 ; ++i)
iNumbers.push_back(i);
std::for_each(iNumbers.begin() , iNumbers.end() , sample() );
}
Output is:
Constructor
0 ,
1 ,
2 ,
3 ,
4 ,
Constructor (copy)
Destructor
Destructor
The reason is that std::for_each takes its argument by value, and this results in a copy of the argument you provide being made.
Therefore, the destruction of the temporary you create by doing sample() will be responsible for one of those two destruction messages (the last one, since the temporary is destructed after the evaluation of the full expression that creates it).
The first destruction message, on the other hand, comes from the destruction of the copy that std::for_each is working on.
std::for_each will take the function object by value, causing it to be copied. So one destructor is called for the temporary object created by sample() and the other for the copy.
If you wrote a copy constructor, you would see that the functor is copied into the algorithm. Both copies are then destructed. There is a potential for the functor to be returned and there would be 3 copies, so one of the copies is being elided.