当前位置: 首页 > 知识库问答 >
问题:

从const右值移动

费秦迟
2023-03-14

我遇到了一些代码,在一个以lambda传递的函数参数中使用const右值引用std::function。令人困惑的部分是,它随后对传递的参数有一个std::移动调用。类似于这样:

using CallbackFn = std::function<void()>;
using AnotherCbFn = std::function<void(int)>;

void bar(AnotherCbFn&& cb) {
    // doSomething();
}

void foo(CallbackFn const&& cb) {
    // Some code
    bar([ x = std::move(cb) /* <-- What's this? */](int value){
        x();
    });
}

void baz() {
    foo([](){
        // doSomethingMore();
    });
}

传入常量值引用,然后对其调用std::move的目的是什么?因此,我尝试了一个更简单的代码片段,以了解在这种情况下会发生什么

#include <utility>
#include <string>
#include <cstdio>
#include <type_traits>

struct Foo {
    Foo() = default;

    Foo(Foo&& o) {
        str = std::move(o.str); // calls the move assignment operator
        std::printf("Other [%s], This [%s]\n", o.str.data(), str.data());
    }

    Foo(Foo const&& o) {
        str = std::move(o.str); // calls the copy assignment operator
        std::printf("Other [%s], This [%s]\n", o.str.data(), str.data());
    }

    private:
    std::string str = "foo";
};

template <typename T>
void f(T&& x) {
    if constexpr(std::is_const_v<T>) {
        std::printf("Const rvalue\n");
        auto temp = std::move(x);
    } else {
        std::printf("non-const rvalue\n");
        auto temp = std::move(x);        
    }
}

Foo const getConstRvalue() {
    return Foo();
}

Foo getNonConstRvalue() {
    return Foo();
}

int main() {
    f(getConstRvalue());
    f(getNonConstRvalue());
}

产生了以下输出:

Const rvalue
Other [foo], This [foo]
non-const rvalue
Other [], This [foo]

在godbolt(此处)检查组件,确认发生了什么。Foo(const

调用标准::\u cxx11::basic\u字符串

虽然Foo(Foo

调用标准::\u cxx11::basic\u字符串

我想(请纠正我!)常量左值函数参数也可以绑定到常量右值参数(以及非常量右值、常量左值和非常量左值),这就是为什么在Foo(const

那么,传递const-rvalue引用,然后对其调用std::move的目的是什么,因为调用std::move通常意味着在此之后不应该使用该值,在这种情况下,实际上涉及的是一个副本,而不是所需的移动语义?是否存在某种微妙的语言机制?


共有1个答案

管翼
2023-03-14

std::移动什么也不移动,它只是将左值(引用右值cb)重新解释为右值,这是您忘记在代码片段中显示的某个柱函数所期望的。

我怀疑它看起来像:

void bar(CallbackFn const&& cb) {
  ...
}
 类似资料:
  • 问题内容: 我试图在Java代码中用php(来自Java语言的DataOutputStream)实现php中的DataOutputStream,它们会像这样>> 在PHP中,我只能像这样>> 我如何在php中做到这一点? 谢谢 问题答案: 您可以使用带符号的移位运算符来实现无符号的右移位运算符的行为,如下所示: 的值是零扩展的右移位位置。如果为正,则结果与; 相同。如果是负的,其结果是等于表达的,

  • 我试图理解“有效现代C”中关于特殊成员函数生成的第17项,所以我尝试了一些示例,并试图对一些行为进行推理。书中说: ..当我提到移动操作move构造或移动分配一个数据成员或基类时,不能保证实际会发生移动。“Memberwise移动”实际上更像Memberwise移动请求,因为未启用移动的类型(即,对移动操作不提供特殊支持的类型,例如大多数C 98遗留类)将通过其复制操作“移动”。。。此外,不会为任

  • 为什么C委员会决定常量引用应该延长临时人员的寿命? 这个事实已经在网上被广泛讨论过了,包括在stackoverflow上。解释这种情况的权威资源可能是这个GoTW: GotW#88:“最重要常量”的候选人 这种语言特征的基本原理是什么?知道了吗? (另一种选择是,临时人员的寿命不会因任何引用而延长。) 我个人最喜欢的理论是,这种行为允许对象隐藏实现细节。有了这个规则,成员函数可以在返回一个值或一个

  • 上篇中,主要讲解了右值引用和移动语义的具体定义和用法。在C++11中几乎所有的容器都实现了移动语义,以方便性能优化。本文以C++11容器中的insert方法为例,详细讲解在容器中移动语义是如何提高性能的,同时,在这个过程中STL又解决了什么问题。 测试性能 MyString类和MyStringNoMove类 创建两个类,其中MyString类提供了拷贝构造函数、移动构造函数,而MyStringNo

  • 在C++11,引入了右值引用的概念,在此基础上的移动语义在STL容器中使用非常广泛。简单来说,move语义使得你可以用廉价的move赋值替代昂贵的copy赋值,完美转发使得可以将传来的任意参数转发给其他函数。然而,这些新特性的背后是什么深意和原理呢?将从两篇博文中做详细的介绍。 左值右值基础 左值和右值 左值是一般指表达式结束后依然存在的持久化对象,右值指表达式结束时就不再存在的临时对象。区分左值

  • 当你第一次了解到移动语义和完美转发的时候,它们看起来非常直观: 移动语义使编译器有可能用廉价的移动操作来代替昂贵的复制操作。正如复制构造函数和复制赋值操作符给了你赋值对象的权利一样,移动构造函数和移动赋值操作符也给了控制移动语义的权利。移动语义也允许创建只可移动(move-only)的类型,例如std::unique_ptr, std::future 和 std::thread。 完美转发使接收任