相关疑难解决方法(0)

什么是右值,左值,x值,glvalues和prvalues?

在C++ 03中,表达式是rvaluelvalue.

在C++ 11中,表达式可以是:

  1. 右值
  2. 左值
  3. x值
  4. glvalue
  5. prvalue

两类已成为五大类.

  • 这些新的表达类别是什么?
  • 这些新类别如何与现有的左值和左值类别相关联?
  • C++ 0x中的右值和左值类别是否与它们在C++ 03中的相同?
  • 为什么需要这些新类别?是WG21神只是想迷惑我们凡人?

c++ expression c++-faq c++11

1291
推荐指数
13
解决办法
17万
查看次数

移动物体比复制更快的原因是什么?

我听过斯科特迈耶斯说" std::move()什么都不动"......但我还没明白这意味着什么.

所以要指出我的问题,请考虑以下事项:

class Box { /* things... */ };

Box box1 = some_value;
Box box2 = box1;    // value of box1 is copied to box2 ... ok
Run Code Online (Sandbox Code Playgroud)

关于什么:

Box box3 = std::move(box1);
Run Code Online (Sandbox Code Playgroud)

我确实理解左值和左值的规则,但我不明白的是记忆中实际发生了什么?它只是以某种不同的方式复制价值,共享地址或什么?更具体地说:什么使移动比复制更快?

我只是觉得理解这一点会让一切都清楚.提前致谢!

编辑:请注意,我不是在询问std::move()实现或任何语法的东西.

c++ move rvalue

34
推荐指数
2
解决办法
1万
查看次数

为什么使用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
查看次数

是否有可能std :: move本地堆栈变量?

请考虑以下代码:

struct MyStruct
{
    int iInteger;
    string strString;
};

void MyFunc(vector<MyStruct>& vecStructs)
{
    MyStruct NewStruct = { 8, "Hello" };
    vecStructs.push_back(std::move(NewStruct));
}

int main()
{
    vector<MyStruct> vecStructs;
    MyFunc(vecStructs);
}
Run Code Online (Sandbox Code Playgroud)

为什么这样做?

在调用MyFunc时,返回地址应放在当前线程的堆栈上.现在创建NewStruct对象,它也应该被放置在堆栈上.使用std :: move,我告诉编译器,我不打算再使用NewStruct引用了.他可以偷走记忆.(push_back函数是具有移动语义的函数.)

但是当函数返回并且NewStruct超出范围时.即使编译器不会从堆栈中删除最初存在的结构所占用的内存,他至少也要删除先前存储的返回地址.

这将导致碎片堆栈,未来的分配将覆盖"移动"的内存.

有人可以向我解释一下吗?


编辑:首先:非常感谢您的回答.但是从我学到的东西,我仍然无法理解,为什么以下不能像我期望的那样工作:

struct MyStruct
{
    int iInteger;
    string strString;
    string strString2;
};

void MyFunc(vector<MyStruct>& vecStructs)
{
    MyStruct oNewStruct = { 8, "Hello", "Definetly more than 16 characters" };
    vecStructs.push_back(std::move(oNewStruct));

    // At this point, oNewStruct.String2 should be "", because its memory was stolen.
    // But only …
Run Code Online (Sandbox Code Playgroud)

c++ move move-semantics c++11

20
推荐指数
2
解决办法
1万
查看次数

何时在`std :: move()`函数中调用移动构造函数?

该功能std::move()定义为

template<typename T>
typename std::remove_reference<T>::type&& move(T && t)
{ 
    return static_cast<typename std::remove_reference<T>::type&&>( t ); 
}
Run Code Online (Sandbox Code Playgroud)

有四个地方我可以想象要调用的移动构造函数:

  1. 参数传递时.
  2. 演员表演时.
  3. 返回结果时.
  4. 不在std::move()函数本身,但可能在返回的引用最终到达的位置.

我敢打赌4号,但我不是百分百肯定,所以请解释你的答案.

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

13
推荐指数
1
解决办法
688
查看次数

通过值,引用和右值传递字符串

我只是比较将字符串传递给函数的性能。该基准测试结果很有趣。

这是我的代码:

void add(std::string msg)
{
    msg += "world";
}

void addRvalue(std::string&& msg)
{
    msg += "world";
}

void addRef(std::string& msg)
{
    msg += "world";
}

void StringCreation() {
    add(std::string("hello "));
}

void StringCopy() {
    std::string msg("hello ");
    add(msg);
}

void StringMove() {
    std::string msg("hello ");
    add(std::move(msg));
}

void StringRvalue() {
    std::string msg("hello ");
    addRvalue(std::move(msg));
}

void StringReference() {
    std::string msg("hello ");
    addRef(msg);
}
Run Code Online (Sandbox Code Playgroud)

StringCreation(),StringRvalue()和StringReference()是等效的。我很惊讶StringMove()是性能最低的-比涉及复制的值传递差。

我是否认为调用StringMove()涉及一个移动构造函数,然后在调用add()时涉及一个复制构造函数,对吗?它不仅仅涉及一举动的构造函数吗?我以为搬家的建设很便宜。

更新资料

我增加了传递给add()的字符串的长度,这确实有所作为。现在,StringMove()仅比StringCreation和StringReference慢1.1倍。StringCopy现在是最糟糕的,这正是我所期望的。

这是新的基准测试结果

因此,StringMove根本不涉及复制-仅适用于小字符串。

c++ stdstring c++11

9
推荐指数
1
解决办法
169
查看次数

复制和移动构造函数之间的效率差异

C++ 11引入了一个新的rvalue引用概念.我正在某处读它,发现如下:

class Base
{
public:
    Base()  //Default Ctor
    Base(int t)  //Parameterized Ctor

    Base(const Base& b)  //Copy Ctor
    Base(Base&& b)  //Move Ctor
};

void foo(Base b)     //Function 1
{}

void foo(Base& b)   //Function 2
{}

int main()
{
    Base b(10);
    foo(b);        -- Line 1 (i know of ambiquity but lets ignore for understanding purpose)
    foo(Base());   -- Line 2
    foo(2) ;       -- Line 3
}
Run Code Online (Sandbox Code Playgroud)

现在我的理解有限,我的观察结果如下:

  1. 第1行将简单地调用复制构造函数,因为参数是左值.

  2. 在C++ 11之前的第2行会调用复制构造函数和所有那些临时复制内容,但是定义了移动构造函数,这里将调用它.

  3. 第3行将再次调用move构造函数,因为2将隐式转换为Base类型(rvalue).

请纠正并解释上述任何观察结果是否错误.

现在,这是我的问题:

  1. 我知道一旦我们移动一个物体,它的数据就会在呼叫位置丢失.所以,我在上面的例子中如何更改第2行以在foo中移动对象"b"(是否使用std :: move(b)?).

  2. 我读过移动构造函数比复制构造函数更有效.怎么样?我只能想到在移动构造函数的情况下我们在堆上有内存的情况不需要再分配.当我们在堆上没有任何内存时,这个陈述是否成立?

  3. 它是否比通过引用传递更有效(不,对吧?)?

c++ c++11

6
推荐指数
1
解决办法
1782
查看次数

从类返回可移动成员变量

class foo{
public:
    bar steal_the_moveable_object();
private:
    bar moveable_object;
};

main(){
    foo f;
    auto moved_object= f.steal_the_moveable_object();
}
Run Code Online (Sandbox Code Playgroud)

如何实现steal_the_movebale_object移动moveable_objectmoved_object

c++ move-semantics c++11

6
推荐指数
1
解决办法
487
查看次数

范围结束时的左值是否可以视为右值?

编辑:考虑以下两个例子:

std::string x;
{
    std::string y = "extremely long text ...";
    ...
    x = y; // *** (1)
}
do_something_with(x);
Run Code Online (Sandbox Code Playgroud)
struct Y
{
    Y();
    Y(const Y&);
    Y(Y&&);
    ... // many "heavy" members
};

struct X
{
    X(Y y) : y_(std::move(y)) { }
    Y y_;
}

X foo()
{
    Y y;
    ...
    return y; // *** (2)
}
Run Code Online (Sandbox Code Playgroud)

y在线(1)和(2)的两个例子中,它的寿命接近结束并且即将被破坏.很明显,它可以被视为右值并在两种情况下都可以移动.在(1)中,它的内容可以移入x和移入(2)到temp的实例中X().y_.

我的问题是:

1)是否会在上述任何一个示例中移动?(a)如果是,则采用何种标准规定.(b)如果不是,为什么不呢?这是标准中的遗漏还是我没有想到的另一个原因?

2)如果上述答案为否.在第一个例子中,我可以改变(1)x = std::move(y)以强制编译器执行移动.在第二个示例中,我可以做什么来向编译器指示y可以移动?return std::move(y)

注意:我故意返回(2)中的实例Y而不是X …

c++ lvalue-to-rvalue c++14

6
推荐指数
1
解决办法
237
查看次数

为什么 list&lt;unique_ptr&gt; 中 unique_ptr 的 std::move() 没有真正移动它?

using Ptr = std::unique_ptr<int>;

Ptr f(bool arg) {
  std::list<Ptr> list;
  Ptr ptr(new int(1));
  list.push_back(std::move(ptr));

  if (arg) {
    Ptr&& obj1 = std::move(list.front());
    // Here |obj1| and |list.front()| still point to the same location!
    list.pop_front();
    return std::move(obj1);
  }
  else {
    Ptr obj2 = std::move(list.front());
    list.pop_front();
    return obj2;
  }
};

Ptr&& ptr1 = f(true);   // |ptr1| is empty.
Ptr&& ptr2 = f(false);  // |ptr2| is fine.
Run Code Online (Sandbox Code Playgroud)

完整来源在这里

我不明白-为什么obj1,并list.front()仍然指向相同的位置后,std::move()被称为?

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

5
推荐指数
1
解决办法
2410
查看次数