这个成语是什么,什么时候应该使用?它解决了哪些问题?当使用C++ 11时,成语是否会改变?
虽然在许多地方已经提到过,但我们没有任何单一的"它是什么"问题和答案,所以在这里.以下是前面提到的地方的部分列表:
c++ c++-faq copy-constructor assignment-operator copy-and-swap
我们x是某种类型的先前已初始化的变量.是以下行:
x = std::move(x)
Run Code Online (Sandbox Code Playgroud)
未定义?这个标准在哪里?它对它有什么看法?
如何在STL中实现交换功能?它是这么简单:
template<typename T> void swap(T& t1, T& t2) {
T tmp(t1);
t1=t2;
t2=tmp;
}
Run Code Online (Sandbox Code Playgroud)
在其他帖子中,他们谈论为您自己的班级专门化这个功能.我为什么要这样做?为什么我不能使用这个std::swap功能?
C++ 11标准对标准库相关的自移动赋值有何看法?更具体的是,什么(如果有的话)保证什么selfAssign呢?
template<class T>
std::vector<T> selfAssign(std::vector<T> v) {
v = std::move(v);
return v;
}
Run Code Online (Sandbox Code Playgroud) 这个问题是基于Scott Meyers最近发表的博客文章.
看起来"显而易见" std::swap(x, x)应该x在C++ 98和C++ 11中保持不变,但我无法在任何标准中找到任何保证.C++ 98 std::swap在复制构造和复制赋值方面进行了定义,而C++ 11则根据移动构造和移动赋值来定义它,这似乎是相关的,因为在C++ 11(和C++ 14)中,17.6 .4.9表示移动分配不需要自我分配安全:
如果函数参数绑定到右值引用参数,则实现可以假定此参数是对此参数的唯一引用.... [注意:如果程序在将左值传递给库函数时将左值转换为x值(例如通过使用参数move(x)调用函数),程序实际上要求该函数将该左值视为暂时的.实现可以自由地优化别名检查,如果参数是左值,则可能需要这些检查. - 尾注]
引起这种措辞的缺陷报告使结果清晰:
这澄清了移动赋值运算符不需要执行复制赋值运算符中常见(并且需要)的传统if(this!=&rhs)测试.
但是在C++ 11和C++ 14中,std::swap预计会使用这个实现,
template<typename T>
void swap(T& lhs, T& rhs)
{
auto temp(std::move(lhs));
lhs = std::move(rhs);
rhs = std::move(temp);
}
Run Code Online (Sandbox Code Playgroud)
并且第一个赋值是对self进行赋值,其中参数是rvalue.如果移动赋值运算符T遵循标准库的策略并且不担心赋值给自己,那么这似乎可以判断未定义的行为,这也意味着它std::swap(x, x)也会具有UB.
即使是孤立的,这也是令人担忧的,但是如果我们认为std::swap(x, x)在C++ 98中应该是安全的,那么这也意味着C++ std::swap11/14可以默默地破坏C++ 98代码.
所以std::swap(x, x)保证x保持不变?在C++ 98中?在C++ 11中?如果是,那么它如何与17.6.4.9的移动分配许可相互作用而不是自我分配安全的?
如本回答所述,复制和交换习惯用法如下实现:
class MyClass
{
private:
BigClass data;
UnmovableClass *dataPtr;
public:
MyClass()
: data(), dataPtr(new UnmovableClass) { }
MyClass(const MyClass& other)
: data(other.data), dataPtr(new UnmovableClass(*other.dataPtr)) { }
MyClass(MyClass&& other)
: data(std::move(other.data)), dataPtr(other.dataPtr)
{ other.dataPtr= nullptr; }
~MyClass() { delete dataPtr; }
friend void swap(MyClass& first, MyClass& second)
{
using std::swap;
swap(first.data, other.data);
swap(first.dataPtr, other.dataPtr);
}
MyClass& operator=(MyClass other)
{
swap(*this, other);
return *this;
}
};
Run Code Online (Sandbox Code Playgroud)
通过将MyClass的值作为operator =的参数,可以通过复制构造函数或移动构造函数构造参数.然后,您可以安全地从参数中提取数据.这可以防止代码重复并有助于异常安全.
答案提到您可以在临时中交换或移动变量.它主要讨论交换.但是,交换(如果未由编译器优化)涉及三个移动操作,而在更复杂的情况下,还需要额外的额外工作.当你想要的时候,就是将临时文件移动到assign-to对象中.
考虑这个更复杂的例子,涉及观察者模式.在这个例子中,我手动编写了赋值运算符代码.重点是移动构造函数,赋值运算符和交换方法:
class MyClass : Observable::IObserver …Run Code Online (Sandbox Code Playgroud) 关于移动分配的标准库策略是允许实现假设永远不会发生自我分配 ; 在我看来这是一个非常糟糕的主意,因为:
remove_if家庭中的任何事情都需要照顾这个角落的情况;那么,为什么这样的决定呢?
¹特别是在库代码中,实现者可以自由地利用关于"分支预期结果"的编译器特定提示(在VC++ __builtin_expect中的gcc/__assume中).
我看到许多代码在复制和交换方面实现了五个规则,但我认为我们可以使用移动函数来替换交换函数,如下面的代码所示:
#include <algorithm>
#include <cstddef>
class DumbArray {
public:
DumbArray(std::size_t size = 0)
: size_(size), array_(size_ ? new int[size_]() : nullptr) {
}
DumbArray(const DumbArray& that)
: size_(that.size_), array_(size_ ? new int[size_] : nullptr) {
std::copy(that.array_, that.array_ + size_, array_);
}
DumbArray(DumbArray&& that) : DumbArray() {
move_to_this(that);
}
~DumbArray() {
delete [] array_;
}
DumbArray& operator=(DumbArray that) {
move_to_this(that);
return *this;
}
private:
void move_to_this(DumbArray &that) {
delete [] array_;
array_ = that.array_;
size_ = that.size_;
that.array_ = nullptr;
that.size_ …Run Code Online (Sandbox Code Playgroud) 此时,编写复制构造函数和赋值运算符对是明确定义的; 快速搜索将引导您充分了解如何正确编码这些.
既然移动构造函数已进入组合,是否有一种新的"最佳"方式?
示例代码:
#include <iostream>
int main()
{
std::vector<int> w(20, 123), x;
w = std::move(w);
std::cout << w.size() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
g ++ 4.8.3上的输出: 0
当然,标准说移动赋值运算符使操作数处于未指定状态.例如,如果代码是x = std::move(w);那么我们期望w.size()为零.
但是,是否有指定的排序或其他条款涵盖自动案件?是否未指定大小是否为0或20其他内容或未定义的行为?标准容器在这里有任何定义的语义吗?
相关:此线程讨论您是否应该关心自己的类中的自动移动,但不讨论标准容器的移动赋值运算符是否执行,并且不提供标准引用.
NB.这与功能完全相同w = static_cast< std::vector<int> && >(w);或std::move不同吗?
对于课程A,我们可以使用
A& operator=( A other ) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
代替
A& operator=( const A& other ) { /* ... */ }
A& operator=( const A&& other ) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
没有恶化的表现或其他负面影响?
我是 C++11 的新手,所以我仍然在努力解决它的概念。
这是我的问题:
我有一个矩阵类:
class matrix
{
private:
double** data;
size_t number_lines;
size_t number_columns;
size_t capacity_lines;
size_t capacity_columns;
public:
....
}
Run Code Online (Sandbox Code Playgroud)
我提供了一个复制构造函数,一个移动构造函数......
我重载了乘法运算符 *(double x) 以将矩阵元素乘以标量 x 并返回相乘后的矩阵。这是代码:
matrix matrix::operator*(double lambda)
{
double** aux_data = new double*[number_lines];
for (size_t i = 0; i < number_lines; i++)
{
aux_data[i] = new double[number_columns];
for (size_t j = 0; j < number_columns; j++)
aux_data[i][j] = lambda*data[i][j];
}
return matrix(aux_data, number_lines, number_columns);
}
Run Code Online (Sandbox Code Playgroud)
函数的返回是一个右值引用,因此它调用移动构造函数。这是移动构造函数的代码:
matrix::matrix(const matrix&& moved_copy)
{
if (this != &moved_copy)
{ …Run Code Online (Sandbox Code Playgroud) 我编写了一个代码,用于动态分配名称.我知道我应该在这种情况下处理深层复制.我写的是我自己的Copy Constructor,Copy Assignment Operator和析构函数.我应该重新定义任何其他隐式函数,例如移动赋值运算符.我不清楚Move Assignment Operator的概念或任何其他隐式定义的成员函数(除了我已经提到的).任何人都可以为此添加代码dynName code,以显示移动赋值运算符或任何其他隐式成员函数(如果有).
#include <iostream>
using namespace std;
class dynName{
char* name;
int size;
public:
dynName(char* name="")
{
int n=strlen(name)+1;
this->name= new char[n];
strncpy(this->name,name,n);
size=n;
name[size-1]='\0';//NULL terminated
cout << "Object created (Constructor) with name : "
<< name << " at address " << &(this->name) << endl;
}
dynName(const dynName& Ob)//Copy Constructor
{
int n=Ob.size;
this->name= new char[n];
strncpy(this->name,Ob.name,n);
size=n;
cout << "Object created(Copy constructor) with name : "
<< this->name << " …Run Code Online (Sandbox Code Playgroud)