§27.7.3.9为以下内容定义以下重载operator<<:
template <class charT, class traits, class T>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>&& os, const T& x);
Run Code Online (Sandbox Code Playgroud)
效果:
os << x
退货:os
(§27.7.2.6定义rvalue重载operator>>.)
基本上,它只是转发到左值超载.我认为这个重载非常危险(实际上istream比ostream实际更重要),请考虑以下内容:
#include <sstream>
#include <iostream>
int main(){
auto& s = (std::stringstream() << "hi there!\n");
std::cout << s.rdbuf(); // oops
}
Run Code Online (Sandbox Code Playgroud)
关于Ideone的实例(未定义行为的完美示例.在MSVC10上没有为我打印).
上面的例子看起来做作,但它不应该太难进入这个情况在通用代码或传递时(std::stringstream() << "text"),以提供一个左值和一个右值过载和存储功能std::ostream或std::istream以不同的方式根据过载.
现在,又将返回a basic_ostream<charT, traits>&&并指定以下内容的参数是什么?
返回: move(os)
(同样的basic_istream.)
有什么我可以忽略的吗?在目前的状态,在我看来,它看起来很危险,就像一个缺陷.我浏览了LWG问题列表并找到了这个提议(嗨@HowardHinnant!).它确实会返回一个右值,但是只为能够链这个特殊的运营商,而不是专门针对我上面描述的安全问题(尽管它肯定是额外的好处,确实 …
这是一个右值参考:
void foo(int&& a);
Run Code Online (Sandbox Code Playgroud)
它不绑定到左值:
int i = 42;
foo(i); // error
Run Code Online (Sandbox Code Playgroud)
这是一个普遍的参考:
template<typename T>
void bar(T&& b);
Run Code Online (Sandbox Code Playgroud)
它绑定到右值,它也绑定到左值:
bar(i); // okay
Run Code Online (Sandbox Code Playgroud)
这是一个右值参考:
template<typename T>
struct X
{
void baz(T&& c);
};
Run Code Online (Sandbox Code Playgroud)
它不绑定到左值:
X<int> x;
x.baz(i); // error
Run Code Online (Sandbox Code Playgroud)
为什么通用引用使用与右值引用相同的语法?这不是一个不必要的混乱来源吗?难道该委员会曾经考虑替代语法像T&&&,T&*,T@或T&42(开玩笑的对最后一个)?如果是这样,拒绝替代语法的原因是什么?
c++ language-design rvalue-reference c++11 forwarding-reference
"标准还为成员函数调用参考限定符"的最常见用例是"用于*this的rvalue引用"?
顺便说一句,有关于这个语言功能一个很好的解释在这里.
我一直在测试一些C++ 11的一些功能.我遇到了r值引用并移动构造函数.
我实现了我的第一个移动构造函数,这里是:
#include <iostream>
#include <vector>
using namespace std;
class TestClass{
public:
TestClass(int s):
size(s), arr(new int[s]){
}
~TestClass(){
if (arr)
delete arr;
}
// copy constructor
TestClass(const TestClass& other):
size(other.size), arr(new int[other.size]){
std::copy(other.arr, other.arr + other.size, arr);
}
// move constructor
TestClass(TestClass&& other){
arr=other.arr;
size=other.size;
other.arr=nullptr;
other.size=0;
}
private:
int size;
int * arr;
};
int main(){
vector<TestClass> vec;
clock_t start=clock();
for(int i=0;i<500000;i++){
vec.push_back(TestClass(1000));
}
clock_t stop=clock();
cout<<stop-start<<endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
代码工作正常.无论如何把一个std :: cout放在复制构造函数中我注意到它被调用了!并且很多次..(移动构造函数500000次,复制构造函数524287次).
让我感到惊讶的是,如果我从代码中注释掉复制构造函数,整个程序会更快,而这次移动构造函数被称为1024287次.
任何线索?
C++ 11使得基于引用限定符重载成员函数成为可能:
class Foo {
public:
void f() &; // for when *this is an lvalue
void f() &&; // for when *this is an rvalue
};
Foo obj;
obj.f(); // calls lvalue overload
std::move(obj).f(); // calls rvalue overload
Run Code Online (Sandbox Code Playgroud)
我理解这是如何工作的,但它的用例是什么?
我看到N2819建议将标准库中的大多数赋值运算符限制为左值目标(即向赋值运算符添加" &"引用限定符),但这被拒绝了.所以这是一个潜在的用例,委员会决定不再使用它.那么,再一次,什么是合理的用例?
我发布了这个答案:https://stackoverflow.com/a/28459180/2642059其中包含以下代码:
void foo(string&& bar){
string* temp = &bar;
cout << *temp << " @:" << temp << endl;
}
Run Code Online (Sandbox Code Playgroud)
是bar左值还是左值?
我问,因为我显然不能取rvalue的地址,但我可以在这里完成rvalue引用的地址.
如果你可以对左值参考执行任何操作,你可以在左值参考上区分用"&&"而不仅仅是"&"来区分两者?
我正在审查一些像这样的代码,其中A是一个可移动的类型:
// Returns true exactly when ownership of a is taken
bool MaybeConsume(A&& a) {
if (some condition) {
Consume(std::move(a)); // ???
return true;
}
return false;
}
// ... elsewhere ...
A a;
if (!MaybeConsume(std::move(a))) {
a.DoSomething(); // !!!
}
Run Code Online (Sandbox Code Playgroud)
我们的静态分析工具抱怨a在移动(at !!!)后使用.IIUC std::move只是一个static_cast,并且在调用a移动构造函数或赋值运算符(可能是在Consume)之前,该对象实际上不会被删除.假设MaybeConsume在评论中满足合同,
std::move在???无操作?(可能这个特殊的实例可以重构以避免微妙,但我仍然想要求我自己的理解).
当给出以下结构的代码时
template <typename... Args>
void foo(Args&&... args) { ... }
Run Code Online (Sandbox Code Playgroud)
我经常static_cast<Args&&>在函数中看到库代码用于参数转发.通常,对此的理由是使用static_cast避免不必要的模板实例化.
鉴于语言的参考折叠和模板扣除规则.我们得到了完美的转发,static_cast<Args&&>这个声明的证据如下(在误差范围内,我希望答案会启发)
&& &&- > &&(1上面的规则)& &&- > &(2上面的规则)这基本上foo()是bar()在上面的例子中转发参数.这也是你在std::forward<Args>这里使用时会得到的行为.
问题 -为什么要std::forward在这些背景下使用?避免额外的实例化是否有理由违反惯例?
Howard Hinnant的论文n2951规定了6个约束,在这些约束条件下,任何实现都std::forward应该"正确".这些曾经是
(1)和(2)证明与static_cast<Args&&>上述方法一起正常工作.(3) - (6)这里不适用,因为在推导的上下文中调用函数时,这些都不会发生.
注意:我个人更喜欢使用std::forward,但我的理由纯粹是我更喜欢坚持惯例.
考虑以下功能:
Foo foo(Foo x)
{
return x;
}
Run Code Online (Sandbox Code Playgroud)
会return x调用复制构造函数还是移动构造函数?(让我们把NRVO留在这里.)
为了调查,我写了一个Foo只能移动但不可复制的简单类:
struct Foo
{
Foo() = default;
Foo(const Foo&) = delete;
Foo(Foo&&) = default;
};
Run Code Online (Sandbox Code Playgroud)
如果在按值返回值参数时调用了移动构造函数,则一切都应该没问题.但是当前的g ++编译器抱怨return x以下错误消息:
error: deleted function 'Foo::Foo(const Foo&)'
Run Code Online (Sandbox Code Playgroud)
如果我更换return x用return std::move(x),一切都很好.由此我得出结论,如果需要,必须明确地从值参数移动.g ++的行为是否符合?
我最近一直在研究右值参考,并得出结论,在任何地方使用pass-by-value进行完整的对象复制是非常有利的(为了完整的理由,请参阅例如如何在添加rvalue参考运算符时减少冗余代码重载?而要速度?按值传递!),因为编译器可以自动在如情况下优化复制走f(std::move(a));,其中f被定义为void f(A a);.
传递价值的一个负面后果是,std::move即使在简单的情况下,所有代码都会被弄乱,例如:
void Object::value(A a)
{
value_ = std::move(a);
}
Run Code Online (Sandbox Code Playgroud)
显然,如果我只写下面的内容:
void Object::value(A a)
{
value_ = a;
}
Run Code Online (Sandbox Code Playgroud)
a即使没有提示,编译器也应该很难识别出它的生命周期即将结束,并且不会使用额外的副本来惩罚我.事实上,即使在复杂的函数中,编译器也应该能够识别它.
问题:
C++ 0x标准是否允许此优化?
编译器是否使用它?即使在复杂的情况下,即函数由多行组成?
这种优化的可靠性如何,即我希望编译器能够像我期望编译器应用返回值优化那样使用它吗?
c++ ×10
rvalue-reference ×10
c++11 ×9
c++17 ×1
forwarding ×1
iostream ×1
lvalue ×1
optimization ×1
overloading ×1
qualifiers ×1
rvalue ×1
templates ×1