简体   繁体   English

C ++不允许强制转换为右值引用

[英]C++ disallow cast to rvalue reference

As always with variables which have been std::move 'd, it is unsafe to use them afterwards. 与通常使用std::move变量一样,事后使用它们也不安全。

As I have written a code where I encourage the user to apply std::move on various occasions, I want to avoid that it is used in a wrong way, at least in a few crucial places (so to say selectively "protect against Machiavelli"). 当我编写了鼓励用户在各种场合应用std::move的代码时,我想避免它以错误的方式使用,至少在一些关键的地方使用了这种方式(也就是说,有选择地“防止马基雅维利”)。

Therefore, is the following overload of std::move a valid way to go? 因此,以下std::move重载是一种有效的方法吗? Or would you discourage from using it? 还是您会阻止使用它?

struct A
{
     void do_something() const { /* ... whatever ... */ }
};

namespace std
{
    auto move(A& t) noexcept = delete;
    auto move(A const& t) noexcept = delete;
    //possibly the same for volatile qualifier

    //possibly also specialize static_cast<A const&>, static_cast<A&>, etc.
}

// possibly set up another function "my_private_move"
// which I can use exclusively where it is appropriate.

int main()
{
    A a;
    // auto a_moved = std::move(a);      //disallow move of lvalue ref
    a.do_something();                    //otherwise this could be problematic

    A(A{});                             //direct initialization via move constructor is ok
    auto x2 = A{};                      
}

Your code exhibits undefined behavior, as per [namespace.std]: 根据[namespace.std],您的代码表现出未定义的行为:

The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified. 如果其添加声明或定义到命名空间一个C ++程序的行为是未定义std命名空间内或一个命名空间std除非另有规定。 A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited. 仅当声明依赖于用户定义的类型并且该特殊化满足原始模板的标准库要求且未被明确禁止时,程序才可以将任何标准库模板的模板特殊化添加到命名空间std

Your use case does not fall under the "otherwise specified" umbrella. 您的用例不属于“其他规定”的范畴。 Besides being undefined, it's of questionable value... you're disallowing this: 除了未定义之外,它的价值还值得怀疑...您不允许这样做:

A a; 
f(std::move(a)); 
// just don't use a here

despite that being potentially a performance improvement over f(a) . 尽管这可能会提高f(a)的性能。 But the user can still write the cast explicitly to accomplish the same result: 但是用户仍然可以显式编写强制转换以实现相同的结果:

f(static_cast<A&&>(a)); // slightly more verbose move

As always with variables which have been std::move'd, it is unsafe to use them afterwards 与通常使用std :: move'd的变量一样,事后使用它们是不安全的

That's not true at all. 那根本不是真的。 It's perfectly safe to use things that have been moved from. 使用已转移的内容绝对安全。 There are lots of places where they must be used after being moved from by Standard, for example std::swap or even just destructing locals. 从Standard移走后,有很多地方必须使用它们,例如std::swap甚至只是破坏本地人。

What you can't do is assume that they have any specific valid state. 不能做的是假设它们具有任何特定的有效状态。 But they must have some valid state. 但是它们必须具有一些有效状态。 If you are authoring A and it does not abide by these rules, then A is broken and should be fixed, rather than band-aiding over the problem. 如果您正在编写A ,但它不遵守这些规则,则A会损坏并且应予以修复,而不是对问题进行临时帮助。

A a; A a;
auto a_moved = std::move(a); 自动a_moved = std :: move(a); //disallow move of lvalue ref //禁止左值引用的移动
a.do_something(); a.do_something(); //otherwise this could be problematic //否则这可能会有问题

The point of std::move() is to take an lvalue and return an rvalue so your move constructor or move assignment can be called. std :: move()的要点是获取一个左值并返回一个右值,以便可以调用move构造函数或move赋值。 So either make the move constructor and move assignment deleted or your users just have to know what are they doing. 因此,要么将move构造函数和move分配删除,要么您的用户只需要知道他们在做什么。 Here's some information on std::move() http://en.cppreference.com/w/cpp/utility/move 这是关于std :: move()的一些信息http://en.cppreference.com/w/cpp/utility/move

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM