标签: rvalue-reference

为什么`operator <<`的`basic_ostream`的rvalue重载返回左值引用?

§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>>.)
基本上,它只是转发到左值超载.我认为这个重载非常危险(实际上istreamostream实际更重要),请考虑以下内容:

#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::ostreamstd::istream以不同的方式根据过载.

现在,又将返回a basic_ostream<charT, traits>&&并指定以下内容的参数是什么?

返回: move(os)

(同样的basic_istream.)

有什么我可以忽略的吗?在目前的状态,在我看来,它看起来很危险,就像一个缺陷.我浏览了LWG问题列表并找到了这个提议(嗨@HowardHinnant!).它确实会返回一个右值,但是只为能够链这个特殊的运营商,而不是专门针对我上面描述的安全问题(尽管它肯定是额外的好处,确实 …

c++ iostream rvalue-reference c++11

24
推荐指数
1
解决办法
1284
查看次数

通用引用的语法

这是一个右值参考:

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

24
推荐指数
2
解决办法
1957
查看次数

什么是"*this的右值参考"?

"标准还为成员函数调用参考限定符"的最常见用例是"用于*this的rvalue引用"?

顺便说一句,有关于这个语言功能一个很好的解释在这里.

c++ rvalue-reference c++11

24
推荐指数
2
解决办法
1922
查看次数

C++ 11右值引用也调用了拷贝构造函数

我一直在测试一些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++ rvalue-reference move-constructor c++11

24
推荐指数
2
解决办法
2978
查看次数

在引用限定符上重载成员函数的用例是什么?

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建议将标准库中的大多数赋值运算符限制为左值目标(即向赋值运算符添加" &"引用限定符),但这被拒绝了.所以这是一个潜在的用例,委员会决定不再使用它.那么,再一次,什么是合理的用例?

c++ overloading qualifiers rvalue-reference c++11

24
推荐指数
2
解决办法
3131
查看次数

右值参考被视为左值?

我发布了这个答案: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引用的地址.

如果你可以对左值参考执行任何操作,你可以在左值参考上区分用"&&"而不仅仅是"&"来区分两者?

c++ rvalue lvalue rvalue-reference c++11

23
推荐指数
2
解决办法
3864
查看次数

对象传递给std :: move但是没有从中移动?

我正在审查一些像这样的代码,其中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在评论中满足合同,

  1. 这有用吗?
  2. 是UB吗?
  3. std::move???无操作?

(可能这个特殊的实例可以重构以避免微妙,但我仍然想要求我自己的理解).

c++ undefined-behavior rvalue-reference c++11

23
推荐指数
1
解决办法
755
查看次数

为什么使用std :: forward <T>而不是static_cast <T &&>

当给出以下结构的代码时

template <typename... Args>
void foo(Args&&... args) { ... }
Run Code Online (Sandbox Code Playgroud)

我经常static_cast<Args&&>在函数中看到库代码用于参数转发.通常,对此的理由是使用static_cast避免不必要的模板实例化.

鉴于语言的参考折叠和模板扣除规则.我们得到了完美的转发,static_cast<Args&&>这个声明的证据如下(在误差范围内,我希望答案会启发)

  • 当给出rvalue引用时(或者为了完整性 - 没有像本示例中那样的引用限定条件),这会以这样的方式折叠引用,即结果是rvalue.使用的规则是&& &&- > &&(1上面的规则)
  • 当给定左值引用时,这会以这样的方式折叠引用,即结果是左值.这里使用的规则是& &&- > &(2上面的规则)

这基本上foo()bar()在上面的例子中转发参数.这也是你在std::forward<Args>这里使用时会得到的行为.


问题 -为什么要std::forward在这些背景下使用?避免额外的实例化是否有理由违反惯例?

Howard Hinnant的论文n2951规定了6个约束,在这些约束条件下,任何实现都std::forward应该"正确".这些曾经是

  1. 应该将左值作为左值转发
  2. 应该将右值作为右值转发
  3. 不应该将右值作为左值转发
  4. 应该将更少的cv限定表达式转发给更多cv限定的表达式
  5. 应该将派生类型的表达式转发为可访问的,明确的基类型
  6. 不应转发任意类型的转换

(1)和(2)证明与static_cast<Args&&>上述方法一起正常工作.(3) - (6)这里不适用,因为在推导的上下文中调用函数时,这些都不会发生.


注意:我个人更喜欢使用std::forward,但我的理由纯粹是我更喜欢坚持惯例.

c++ templates forwarding rvalue-reference c++17

23
推荐指数
3
解决办法
1429
查看次数

当按值返回时,值参数是否隐式移动?

考虑以下功能:

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 xreturn std::move(x),一切都很好.由此我得出结论,如果需要,必须明确地从值参数移动.g ++的行为是否符合?

c++ rvalue-reference move-semantics c++11

22
推荐指数
2
解决办法
567
查看次数

当最后一次使用可移动对象时,编译器会自动使用移动语义吗?

我最近一直在研究右值参考,并得出结论,在任何地方使用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即使没有提示,编译器也应该很难识别出它的生命周期即将结束,并且不会使用额外的副本来惩罚我.事实上,即使在复杂的函数中,编译器也应该能够识别它.

问题:

  1. C++ 0x标准是否允许此优化?

  2. 编译器是否使用它?即使在复杂的情况下,即函数由多行组成?

  3. 这种优化的可靠性如何,即我希望编译器能够像我期望编译器应用返回值优化那样使用它吗?

c++ optimization rvalue-reference move-semantics c++11

22
推荐指数
1
解决办法
1585
查看次数