好的,所以我完全接受了复制和交换习语,我想我主要知道如何实现它。
但是,或者代码库使用MFC 的 CString 类作为字符串,这不会改变。
既然swap必须(应该???)不抛出,我不能做
std::swap(this->my_cstring, rhs.my_cstring);
Run Code Online (Sandbox Code Playgroud)
因为这将创建一个可能抛出的临时 CString 对象。(加上它的低效。)
那么我还剩下什么?我应该添加一个try-catch吗?我真的应该允许这种(好吧,非常罕见)内存不足的情况引发异常并使交换失败?
查看 CStrings 实现,似乎没有允许交换的成员或函数......
我有模板类节点,为了遵循复制和交换习惯用法,我尝试编写swap属于friend类的函数Node
我的代码是:
Node.h
#ifndef NODE_H
#define NODE_H
#include<memory>
template<typename type>
class Node
{
type data_;
std::unique_ptr<Node> next_;
public:
Node(type data);
Node(const Node& other);
Node& operator=(Node other);
friend void swap(Node& lhs, Node& rhs);
};
#include "Node.tpp"
#endif
Run Code Online (Sandbox Code Playgroud)
和Node.tpp
template<typename type>
Node<type>::Node(type data):data_(data),next_(nullptr){
}
template<typename type>
Node<type>::Node(const Node& other)
{
data_ = other.data_;
next_ = nullptr;
if(other.next_ != nullptr)
{
next_.reset(new Node(other.next_->data_));
}
}
template<typename type>
void swap(Node<type>& lhs, Node<type>& rhs)
{
using std::swap; …Run Code Online (Sandbox Code Playgroud) 考虑经典的虚拟继承钻石层次结构.我想知道在这种层次结构中复制和交换习语的正确实现是什么.
这个例子有点人为 - 并且它不是很聪明 - 因为它可以很好地使用A,B,D类的默认复制语义.但只是为了说明问题 - 请忘记示例弱点并提供解决方案.
所以我从两个基类(B <1>,B <2>)派生出D类 - 每个B类几乎从A类继承.每个类都有非平凡的复制语义,使用复制和交换习语.派生最多的D类在使用这个习语时有问题.当它调用B <1>和B <2>交换方法时 - 它将虚拟基类成员交换两次 - 所以一个子对象保持不变!
A:
class A {
public:
A(const char* s) : s(s) {}
A(const A& o) : s(o.s) {}
A& operator = (A o)
{
swap(o);
return *this;
}
virtual ~A() {}
void swap(A& o)
{
s.swap(o.s);
}
friend std::ostream& operator << (std::ostream& os, const A& a) { return os << a.s; }
private:
S s;
};
Run Code Online (Sandbox Code Playgroud)
乙
template <int N> …Run Code Online (Sandbox Code Playgroud) c++ multiple-inheritance virtual-inheritance diamond-problem copy-and-swap
在我身上发生了一些我认为完全合理的事情,但是我想要人们对它的看法,以防我完全遗漏某些东西.首先,我的理解T& operator=(T&& rhs)是,当我们完成时,我们不关心内容rhs是什么,只是内容已被移入this并且rhs可以安全地破坏.
话虽这么说,假设交换很便宜,复制赋值运算符的常见异常安全实现看起来像这样:
T& operator=(const T& rhs) {
if(this != &rhs) {
T(rhs).swap(*this);
}
return *this;
}
Run Code Online (Sandbox Code Playgroud)
因此,实现移动赋值运算符的一种自然方式是这样的:
T& operator=(T&& rhs) {
if(this != &rhs) {
T(std::move(rhs)).swap(*this);
}
return *this;
}
Run Code Online (Sandbox Code Playgroud)
但它发生在我身上,rhs不一定是空的!那么,为什么不做一个平原swap呢?
T& operator=(T&& rhs) {
rhs.swap(*this); // is this good enough?
return *this;
}
Run Code Online (Sandbox Code Playgroud)
我认为这满足了移动赋值操作符需要做的...但就像我说的那样,这只是发生在我身上,所以我认为我可能会遗漏一些东西.
我能想到的唯一"缺点"是,this与执行move-construct/swap的版本相比,拥有的东西使用普通交换可能会延长寿命.
思考?
下面什么是复制和交换习惯用法以及如何为我的班级提供交换功能,我尝试实现交换功能,如后面接受的答案选项2(具有调用成员函数的自由函数)而不是直接友好前链接中的自由功能.
但是以下不编译
#include <iostream>
// Uncommenting the following two lines won't change the state of affairs
// class Bar;
// void swap(Bar &, Bar &);
class Bar {
public:
Bar(unsigned int bottles=0) : bottles(bottles) { enforce(); } // (1)
Bar(Bar const & b) : bottles(b.bottles) { enforce(); } // (1)
Bar & operator=(Bar const & b) {
// bottles = b.bottles;
// enforce();
// Copy and swap idiom (maybe overkill in this example)
Bar tmp(b); // …Run Code Online (Sandbox Code Playgroud) c++ copy-constructor assignment-operator copy-and-swap c++11
我正在尝试为我的类实现Copy-and-Swap Idiom,因为我需要实现operator=,因为它有引用成员,并且引用只能分配一次,我认为前面提到的成语是一个有效的解决方法.
但现在我收到了一个构建错误:
>c:\Program Files\Microsoft Visual Studio 10.0\VC\include\utility(102): error C2259: 'IVariables' : cannot instantiate abstract class
1> due to following members:
1> 'IVariables::~IVariables(void)' : is abstract
1> d:\svn.dra.workingcopy\serialport\IVariables.h(6) : see declaration of 'IVariables::~IVariables'
1> 'std::string &IVariables::operator [](const std::string &)' : is abstract
1> d:\svn.dra.workingcopy\serialport\IVariables.h(7) : see declaration of 'IVariables::operator []'
1> 'unsigned int IVariables::getVariableLength(const std::string &) const' : is abstract
1> d:\svn.dra.workingcopy\serialport\IVariables.h(8) : see declaration of 'IVariables::getVariableLength'
1> Message.cpp(32) : see reference to function template instantiation …Run Code Online (Sandbox Code Playgroud) 我上课了
class MyClass
{
public :
int a;
int b;
}
Run Code Online (Sandbox Code Playgroud)
为了使用copy-swap惯用语,我创建了该函数
void MyClass::swap(MyClass& other)
{
std::swap(a,other.a);
std::swap(b,other.b);
}
Run Code Online (Sandbox Code Playgroud)
如果,稍后,我更改了我的类并删除了该成员a,那么编译器会在swap函数中抱怨,这没关系.
但是如果我添加一个新成员,我的swap功能就不再正确了.为了不忘记将新成员添加到交换功能,我该怎么办?
编码
using namespace std;
class A
{
private:
vector<int> a;
public:
A(vector<int> x):a(x){}
string toString()
{
string s;
for (auto& element : a)
{
s += to_string(element) + " ";
}
return s;
}
};
int main()
{
A a1({1,2,3});
A a2({11,12,13});
cout << "a1 = " << a1.toString() << "\n";
cout << "a2 = " << a2.toString() << "\n";
swap(a1,a2);
cout << "a1 = " << a1.toString() << "\n";
cout << "a2 = " << a2.toString() << "\n";
return …Run Code Online (Sandbox Code Playgroud)