使用复制构造函数修复浅拷贝
fixing shallow copy with a copy constructor
我定义了一个复制构造函数以避免对数据成员 n 进行浅表复制,但它不起作用,当我更改 v1 时 v2 仍在更改,我做错了什么?
#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;
}
问题是你的复制构造函数实现错误。您尝试修复浅拷贝问题,但您的代码包含一个声明,该声明再次重新引入相同的问题。
这一行:
n=new int;
您正确地分配了一个新的 int
,没问题。
但是在这条线上:
n=vector.n;
您正在丢弃刚刚分配的 int
,而是将 n
指向另一个向量的 n
指向的相同 int
。这又是浅拷贝问题。
要正确解决此问题,您需要将另一个向量的 n
成员的值 复制到新分配的 n
成员中,例如:
n = new int;
*n = *(vector.n);
或:
n = new int( *(vector.n) );
也就是说,要完全符合 "Rule of 3",您还需要添加一个析构函数来释放 n
(这意味着您 不能 使 v1
指向 main()
中的局部 int
变量),以及添加复制赋值运算符以复制 值 的 n
(类似于复制构造函数)。在 C++11 中,您还可以选择通过添加移动构造函数和移动赋值运算符来遵守 "Rule of 5"。
试试这个:
#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;
}
我定义了一个复制构造函数以避免对数据成员 n 进行浅表复制,但它不起作用,当我更改 v1 时 v2 仍在更改,我做错了什么?
#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;
}
问题是你的复制构造函数实现错误。您尝试修复浅拷贝问题,但您的代码包含一个声明,该声明再次重新引入相同的问题。
这一行:
n=new int;
您正确地分配了一个新的 int
,没问题。
但是在这条线上:
n=vector.n;
您正在丢弃刚刚分配的 int
,而是将 n
指向另一个向量的 n
指向的相同 int
。这又是浅拷贝问题。
要正确解决此问题,您需要将另一个向量的 n
成员的值 复制到新分配的 n
成员中,例如:
n = new int;
*n = *(vector.n);
或:
n = new int( *(vector.n) );
也就是说,要完全符合 "Rule of 3",您还需要添加一个析构函数来释放 n
(这意味着您 不能 使 v1
指向 main()
中的局部 int
变量),以及添加复制赋值运算符以复制 值 的 n
(类似于复制构造函数)。在 C++11 中,您还可以选择通过添加移动构造函数和移动赋值运算符来遵守 "Rule of 5"。
试试这个:
#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;
}