1

我需要一些关于何时分配或列出初始化auto类型命名变量的保证,

  • A a std::move()ed 返回对变量的引用
  • B 对变量的返回引用

在表达式之后,原点超出范围,是 A 安全 / B 不安全。示例代码:

#include <iostream>
#include <string>
#include <deque>
#include <utility>

int main() {
    std::deque<std::string> container {"foo"};
    auto elementB = container.front(); //B I assume this is unsafe
    auto elementA = std::move(container.front());//A I assume this is safe
    container.pop_front();

    std::cout << "A: " << elementA << " B: " << elementB  << "\n";
}

据我了解,表达式 B 生成赋值的左值权利,因此类型elementB是左值引用,也就是左值引用std::string&,因此不安全。

执行代码时“A:foo B:”的输出也表明了这一点。( https://ideone.com/wKKbdK ) 更新:对不起,我忘了我移动了它,所以我改变了顺序,现在输出是例外,对不起。

然而,我不确定的更麻烦的事情是表达式 A:在std::move我假设我得到一个 xvalue 之后,它既是右值又是左值,所以我不确定对于elementA.

因为从左值我几乎可以确定它的 UB,而左值是左值,而 xvalue 是其中的一部分,那么类型将elementAstd::string&&,这不安全吗?(除非 const&& AFAIK 例外)

所以总结一下:elementA 的使用是安全的标准化行为吗?它的类型是什么?

4

2 回答 2

4

elementA 的使用是安全的标准化行为吗?

是的。

...它的类型是什么?

它的类型将是std::string. auto类型推导的工作方式类似于模板类型推导,其中包括删除引用的“引用性”。返回 xvalue的事实std::move(container.front())在这里并没有太大变化。它是一个“过期”值,您可以(a)移动构造一个新对象(就像您当前所做的那样)(b)将其绑定到const-qualified 引用或(c)将其绑定到 rvalue-reference。在这里,(b)和(c)都有效,但没有多大意义,因为它们掩盖了没有任何东西被移动的事实(感谢@MM在这里纠正我)。例子:

auto elementA = std::move(container.front());
// Error, can't bind to non-const reference:
// auto& doesntWork = std::move(container.front());
auto&& thisWorks = std::move(container.front());
const auto& thisWorksToo = std::move(container.front());

请注意,正如@MM 在评论中指出的那样,最后两个引用一旦container.pop_front();遇到就会悬空。

另请注意,elementBas的扣除std::string无助于您取消引用已移动对象(返回 by container.front())这一事实,您应该避免这种情况。

于 2019-06-18T08:28:14.420 回答
2

您的代码很好,因为两者都elementAelementB推断string,而不是引用(string&string&&)。

给定auto elementA,初始化器的引用部分将被忽略。如果您想elementA或被elementB引用,您必须明确指定,例如auto&& elementAor auto& elementB

您可能会将值类别与类型混淆;他们是独立的。初始化器的值类别,即它是左值或右值,不会影响类型推导。在您的代码中, given auto elementAelementA将是 type std::string, given auto& elementA,其类型将是std::string&, given auto&& elementA,其类型将是std::string&&

于 2019-06-18T08:27:55.617 回答