在类的赋值运算符中,通常需要检查所分配的对象是否是调用对象,这样就不会搞砸了:
Class& Class::operator=(const Class& rhs) {
if (this != &rhs) {
// do the assignment
}
return *this;
}
Run Code Online (Sandbox Code Playgroud)
移动赋值运算符需要相同的东西吗?是否有过这样的情况this == &rhs?
? Class::operator=(Class&& rhs) {
?
}
Run Code Online (Sandbox Code Playgroud) 如何从中删除第i项std::vector?
我知道我想删除第i个元素.我int i; and std::vector<process> pList;在那里process是一个结构.我想做一些与以下相同的事情:
pList.remove(i);
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的移动分配许可相互作用而不是自我分配安全的?
以下是可能的定义std::swap:
template<class T>
void swap(T& a, T& b) {
T tmp(std::move(a));
a = std::move(b);
b = std::move(tmp);
}
Run Code Online (Sandbox Code Playgroud)
我相信
std::swap(v,v) 保证没有效果std::swap 可以如上实现.以下引用似乎暗示这些信念是矛盾的.
17.6.4.9函数参数[res.on.arguments]
1除非另有明确说明,否则以下各项均适用于C++标准库中定义的函数的所有参数.
...
- 如果函数参数绑定到右值引用参数,则实现可以假定此参数是对此参数的唯一引用.[注意:如果参数是T &&形式的通用参数并且绑定了类型A的左值,则参数绑定到左值引用(14.8.2.1),因此不包含在前一句中. - 结束注释] [注意:如果程序在将左值传递给库函数时将左值转换为x值(例如通过使用参数move(x)调用函数),程序实际上会要求该函数处理该左值作为临时的.实现可以自由地优化别名检查,如果参数是左值,则可能需要这些检查.-endnote]
(感谢霍华德Hinnant(欣南特)用于提供报价)
让我们v从标准模板库中获取一些可移动类型的对象并考虑该调用std::swap(v, v).在该行a = std::move(b);以上,这是内部的情况T::operator=(T&& t)的是this == &b,这样的参数是不唯一的参考.这违反了上面的要求,因此该行在a = std::move(b)调用时调用未定义的行为std::swap(v, v).
这里有什么解释?
示例代码:
#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不同吗?
有人可以给我提示为什么这段代码没有输出任何东西?我假设它与移动线有关...
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
vector<int> v{66,79,154,24,76,13,7};
v = move(v);
for(auto i: v)
cout << i << " ";
}
Run Code Online (Sandbox Code Playgroud)
更新:所以我添加了系统("暂停"); 帮助自己.我是否需要它并不是我所关注的.当我在Visual Studio 2013中再次运行代码时,它工作正常.但是,当我使用C++ 14运行Ideone时,它没有输出任何内容.现在有点困惑.
我有这个代码似乎工作,但我不确定我是否只是看到未定义的行为或它实际上工作.
#include <string>
#include <vector>
#include <sstream>
#include <numeric>
#include <iostream>
auto main() -> int {
const std::vector<std::string> keywords = {
"and","and_eq","asm","auto","bitand", "bitor","bool","break","case",
"catch","char","class","compl","const", "const_cast","continue",
"default","#define","delete","do","double","dynamic_cast","else","enum",
"explicit","export","extern", "extern \"C\"","false","float",
"for","friend","goto","if","inline","int","long","mutable","namespace",
"new","not","not_eq","operator","or", "or_eq","private","protected",
"public","register","reinterpret_cast","short","signed","sizeof",
"static","static_cast","struct","switch","template","this","throw",
"true","try","typedef","typeid","typename","union","unsigned","using",
"virtual","void","volatile","void","wchar_t","while","xor","xor_eq",
"return", "decltype"
};
std::ostringstream keywords_pattern =
std::accumulate(keywords.begin(), keywords.end(), std::forward<std::ostringstream>(
std::ostringstream("constexpr", std::ostringstream::ate)),
[](std::ostringstream &accum, const std::string& next) -> std::ostringstream&& {
accum << '|' << next;
return std::forward<std::ostringstream>(std::move(accum));
});
std::cout << keywords_pattern.str() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
所有这一切都是将C++关键字的向量组合成一个分隔的字符串|.
这是我运行时的输出:
onstexpr|and|and_eq|asm|auto|bitand|bitor|bool|break|case|catch|char|class|compl|const|const_cast|continue|default|#define|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|extern "C"|false|float|for|friend|goto|if|inline|int|long|mutable|namespace|new|not|not_eq|operator|or|or_eq|private|protected|public|register|reinterpret_cast|short|signed|sizeof|static|static_cast|struct|switch|template|this|throw|true|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|void|wchar_t|while|xor|xor_eq|return|decltype
Run Code Online (Sandbox Code Playgroud)
不, …