在 C++ 中复制一个对象
Copying an object in C++
我想知道相对于复制单个元素,以下列方式复制对象是否可以接受。
#include <iostream>
using namespace std;
class abc{
public:
abc(int a = 10, int b = 5);
abc(const abc &obj, int b = 10);
int ret_x() { return x; }
int ret_y() { return y; }
private:
int x;
int y;
};
abc::abc(int a, int b)
: x(a),
y(b)
{
}
abc::abc(const abc &obj, int b)
{
if (this != &obj) {
*this = obj; -----> Copying the object
}
y = b;
}
int main()
{
abc a1;
cout << "A1 values: " << a1.ret_x() << "\t" << a1.ret_y() << endl;
abc a2(a1, 20);
cout << "A2 values: " << a2.ret_x() << "\t" << a2.ret_y() << endl;
return 0;
}
编辑:
用例:
问题是对象 a1 是自动生成的,因此无法更新 class 中任何新引入的成员。当然,我可以提供一个成员函数来更新新成员,但我想探索这个选项。
代码没问题,但是方法对吗?
谢谢!
正如克里斯在评论中已经指出的那样,您正在创建一个全新的对象。您希望如何将 this
传递给构造函数?好吧,实际上,您也许可以通过 placement new:
abc a;
abc* b = new(&a)abc(a);
但这是一个如此奇特的案例,我不会考虑它,我什至敢于声称使用诸如 placement new 之类的高级东西的人应该知道他在做什么......所以省略 if-check。
在您的特殊情况下,这似乎没问题,因为不存在可能需要深层复制的数据。但是请注意,您分配了成员 b
两次。对于 int 并不是很重要,但是对于进行深度复制的较大对象(std::string、std::vector、...),这变得越来越有问题。
不过,对于 C++11,我更喜欢构造函数委托:
abc::abc(const abc& obj, int b)
: abc(obj) // copying here
{
y = b;
}
但是,这并没有解决双重赋值问题。老实说,这可能并不总是一个真正的问题,在许多情况下,编译器可能会优化第一个赋值(尤其是在我们示例的 int
情况下)。但是对于更复杂的数据类型(可能已经 std::string),依赖编译器检测过时的赋值我会感到不舒服...
请注意,如果您在内部管理资源,您可能会遇到麻烦:
struct abc
{
int* array;
abc() : array(new int[7]) { }
~abc()
{
delete[] array;
}
}
不提供适当的赋值运算符或复制构造函数——取决于实现变体,你的(赋值)或我的(构造函数委托)——进行必要的深度复制将导致多次删除相同的数据(未定义的行为! ).按照rule of three (or more recently, rule of five), you most probably will need both anyway. You might consider the copy and swap idiom成语然后。
最后一个避免双重赋值的技巧:
abc(abc const& other)
: abc(other, other.y)
{ }
abc(abc const& other, int y)
: x(other.x), y(y)
{ }
我想知道相对于复制单个元素,以下列方式复制对象是否可以接受。
#include <iostream>
using namespace std;
class abc{
public:
abc(int a = 10, int b = 5);
abc(const abc &obj, int b = 10);
int ret_x() { return x; }
int ret_y() { return y; }
private:
int x;
int y;
};
abc::abc(int a, int b)
: x(a),
y(b)
{
}
abc::abc(const abc &obj, int b)
{
if (this != &obj) {
*this = obj; -----> Copying the object
}
y = b;
}
int main()
{
abc a1;
cout << "A1 values: " << a1.ret_x() << "\t" << a1.ret_y() << endl;
abc a2(a1, 20);
cout << "A2 values: " << a2.ret_x() << "\t" << a2.ret_y() << endl;
return 0;
}
编辑:
用例:
问题是对象 a1 是自动生成的,因此无法更新 class 中任何新引入的成员。当然,我可以提供一个成员函数来更新新成员,但我想探索这个选项。
代码没问题,但是方法对吗?
谢谢!
正如克里斯在评论中已经指出的那样,您正在创建一个全新的对象。您希望如何将 this
传递给构造函数?好吧,实际上,您也许可以通过 placement new:
abc a;
abc* b = new(&a)abc(a);
但这是一个如此奇特的案例,我不会考虑它,我什至敢于声称使用诸如 placement new 之类的高级东西的人应该知道他在做什么......所以省略 if-check。
在您的特殊情况下,这似乎没问题,因为不存在可能需要深层复制的数据。但是请注意,您分配了成员 b
两次。对于 int 并不是很重要,但是对于进行深度复制的较大对象(std::string、std::vector、...),这变得越来越有问题。
不过,对于 C++11,我更喜欢构造函数委托:
abc::abc(const abc& obj, int b)
: abc(obj) // copying here
{
y = b;
}
但是,这并没有解决双重赋值问题。老实说,这可能并不总是一个真正的问题,在许多情况下,编译器可能会优化第一个赋值(尤其是在我们示例的 int
情况下)。但是对于更复杂的数据类型(可能已经 std::string),依赖编译器检测过时的赋值我会感到不舒服...
请注意,如果您在内部管理资源,您可能会遇到麻烦:
struct abc
{
int* array;
abc() : array(new int[7]) { }
~abc()
{
delete[] array;
}
}
不提供适当的赋值运算符或复制构造函数——取决于实现变体,你的(赋值)或我的(构造函数委托)——进行必要的深度复制将导致多次删除相同的数据(未定义的行为! ).按照rule of three (or more recently, rule of five), you most probably will need both anyway. You might consider the copy and swap idiom成语然后。
最后一个避免双重赋值的技巧:
abc(abc const& other)
: abc(other, other.y)
{ }
abc(abc const& other, int y)
: x(other.x), y(y)
{ }