我想为我的类(我们称之为A)实现一个Swap()方法,使copy-and-swap运算符=()。据我所知,swap方法应该通过交换类的所有成员来实现,例如:
class A
{
public:
void swap(A& rhv)
{
std::swap(x, rhv.x);
std::swap(y, rhv.y);
std::swap(z, rhv.z);
}
private:
int x,y,z;
};
但是如果我有一个const成员,我应该怎么做呢?我不能调用std::swap来获得它,所以我不能编写A::Swap()。
编辑:实际上我的类更复杂一些。我想对它进行序列化和反序列化。常量成员是一段在这个对象中不会改变的数据(例如它的ID)。所以我想写这样的代码:
class A
{
public:
void Serialize(FILE* file) const
{
fwrite(&read_a, 1, sizeof(read_a), file);
}
void Deserialize(FILE* file) const
{
size_t read_a;
fread(&read_a, 1, sizeof(read_a), file);
A tmp(read_a);
this->Swap(tmp);
}
private:
const size_t a;
};
并调用这个代码:
A a;
FILE* f = fopen(...);
a.Deserialize(f);
很抱歉用了这么含糊的措辞。
7条答案
按热度按时间pobjuy321#
我认为你真正需要的是一个内部数据结构,你可以很容易地在对象之间交换。例如:
这会使
A
对象内部数据的任何示例中的z
值保持不变,但是您可以交换两个A
对象的内部数据(包括常量z
值),而不会违反常量正确性。sirbozc52#
在一夜好眠之后,我认为最好的答案是使用一个指向常量值的非常数指针--毕竟这些都是您要捕获的语义。
q43xntqr3#
一个好的设计原则是把你的对象设计成不可变的。这意味着对象一旦创建就不能改变。要“改变”对象,你必须复制对象并确保改变你想要的元素。
也就是说,在这种情况下,您应该考虑使用复制构造函数来复制要交换的对象,然后实际交换对该对象的引用。我可以理解,仅仅能够在幕后更改对象的元素是很诱人的。但是最好是复制一个对象,然后用NEW对象替换对该对象的引用,这样可以避免任何常量的麻烦。
希望这个有用。
9lowa7mx4#
我建议您使用指向示例的指针。指针可以比
class
或struct
中的数据更容易交换。clone
当前对象。给定一个结构体:
我的理解是,您希望交换类似上面
My_Struct
的示例。您可以复制可变(非常数)成员,但不能复制const
成员。更改const
成员的唯一方法是为const
成员创建一个新示例,并为该成员指定一个新值。也许你需要重新考虑你的设计。
enyaitl35#
恕我直言,你必须考虑不要交换CONST成员。
PD:我认为你可以考虑在你的方法中使用反射,这样你就不必维护函数了。
wz8daaqr6#
这就是为什么
const_cast
被创造出来的原因。只要记住不要把你的脚射掉。**编辑:**好吧,我承认- const_cast根本不是为这个问题设计的。这可能对你的编译器有用,但你不能指望它,如果恶魔从你的鼻孔里飞出来,请不要责怪我。
ff29svar7#
tl;dr;:这是未定义的行为。
Reference/reason: CppCon 2017: Scott Schurr “Type Punning in C++17: Avoiding Pun-defined Behavior, @24m52s +- ”
举个例子,我的解释是:
假设你创建了一个
T
类型的对象,它有一些const
成员。你可以把这个对象作为一个非常数引用传递给一个操作它的函数f(&T)
,但是你希望const
成员在调用之后保持不变。swap
可以在非常数引用中调用,并且它可以发生在函数f
内部。打破了对呼叫者的const
成员的前提。使用
swap
的代码的每一部分都必须Assert被交换的T
类型的对象不属于任何假定const
成员为常量的上下文,这不可能自动验证 *。