c – 如何复制(或交换)包含引用或const的成员的类型的对象?
我正在尝试解决的问题是产生容器,例如包含引用和const数据成员的对象的std ::向量:
struct Foo; struct Bar { Bar (Foo & foo,int num) : foo_reference(foo),number(num) {} private: Foo & foo_reference; const int number; // Mutable member data elided }; struct Baz { std::vector<Bar> bar_vector; }; 这不会按原样工作,因为由于引用成员foo_reference和const成员编号,Foo类的默认赋值运算符无法构建. 一个解决方案是将foo_reference更改为指针,并摆脱const关键字.然而,这种引用超出了指针的优点,而且这个const成员真的应该是const.他们是私人会员,所以唯一可以伤害的是我自己的代码,但是我用脚本(或更高版本)用自己的代码开枪. 我已经在网络上看到了解决这个问题的解决方案,其中swap方法看起来充满了基于reinterpret_cast和const_cast的奇迹的未定义的行为.发生这些技术似乎在我的电脑上工作.今天.具有一个特定编译器的特定版本.明天还是用不同的编译器?谁知道.我不会使用依赖于未定义行为的解决方案. stackoverflow的相关答案: > Does it make sense to implement the copy-assignment operator in a class with all const data members? 那么有没有办法为这样的类写一个不调用未定义行为的交换方法/复制构造函数,或者我刚刚搞砸了? 编辑 struct Bar { Bar (Foo & foo,int num) : foo_ptr(&foo),number(num) {} private: Foo * foo_ptr; int number; // Mutable member data elided }; 这显然消除了数字的常数,并消除了foo_reference的隐含常量.这不是我后来的解决方案.如果这是唯一的非UB解决方案,那就可以了.我也很清楚这个解决方案: void swap (Bar & first,Bar & second) { char temp[sizeof(Bar)]; std::memcpy (temp,&first,sizeof(Bar)); std::memcpy (&first,&second,sizeof(Bar)); std::memcpy (&second,temp,sizeof(Bar)); } 然后使用copy-and-swap写入赋值运算符.这会绕过引用和const问题,但它是UB吗? (至少它不使用reinterpret_cast和const_cast.)一些可爱的可变数据是包含std :: vectors的对象,所以我不知道这样一个浅的副本是否会在这里工作. 解决方法
如果您使用移动运算符实现此操作有一种方法:
Bar & Bar :: operator = (Bar && source) { this -> ~ Bar (); new (this) Bar (std :: move (source)); return *this; } 你不应该真正使用这个技巧与复制构造函数,因为它们可以经常抛出,然后这是不安全的.移动构造函数永远不会抛出,所以这应该是可以的. std :: vector和其他容器现在在可能的情况下利用移动操作,所以调整大小和排序等等都可以. 这种方法将允许您保留const和引用成员,但是您仍然无法复制对象.要做到这一点,你必须使用非const和指针成员. 顺便说一句,你不应该像非POD类型那样使用memcpy. 编辑 对未定义行为投诉的回应. 问题情况似乎是 struct X { const int & member; X & operator = (X &&) { ... as above ... } ... }; X x; const int & foo = x.member; X = std :: move (some_other_X); // foo is no longer valid 如果您继续使用foo,那么它是未定义的行为.对我来说这是一样的 X * x = new X (); const int & foo = x.member; delete x; 其中很明显使用foo是无效的. 也许X :: operator =(X&&)的一个天真的阅读会导致你认为可能foo在移动后仍然有效,有点像这样 const int & (X::*ptr) = &X::member; X x; // x.*ptr is x.member X = std :: move (some_other_X); // x.*ptr is STILL x.member 成员指针ptr在x的移动中幸存下来,但是foo没有. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |