Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么右值唯一的运算符*返回左值?_C++_C++11_Undefined Behavior_Unique Ptr_Rvalue Reference - Fatal编程技术网

C++ 为什么右值唯一的运算符*返回左值?

C++ 为什么右值唯一的运算符*返回左值?,c++,c++11,undefined-behavior,unique-ptr,rvalue-reference,C++,C++11,Undefined Behavior,Unique Ptr,Rvalue Reference,使用来自“死”唯一\u ptr的运算符*的返回值是错误的 以下代码进行编译,但当然会导致未定义的行为: auto& ref = *std::make_unique<int>(7); std::cout << ref << std::endl; 在这种情况下,这可以正常工作: std::cout << *std::make_unique<int>(7) << std::endl; std::cout就涉及的价值类别

使用来自“死”唯一\u ptr的运算符*的返回值是错误的

以下代码进行编译,但当然会导致未定义的行为:

auto& ref = *std::make_unique<int>(7);
std::cout << ref << std::endl;
在这种情况下,这可以正常工作:

std::cout << *std::make_unique<int>(7) << std::endl;

std::cout就涉及的价值类别和基本思想而言,您的代码相当于:

auto &ref = *(new int(7));
newint(7)
生成一个指针对象,它是一个prvalue表达式。取消引用该prvalue将导致左值表达式

无论指针对象是右值还是左值,对指针应用
*
都会产生左值。这不应该仅仅因为指针是“智能的”就改变。好问题

在不深入研究相关论文和设计讨论的情况下,我认为以下几点可能是本设计决策的原因:

  • 正如@Nicol Bolas所提到的,这就是内置(原始)指针的行为方式,因此“按
    int
    does做”在这里被应用为“按
    int*
    does做”

    这类似于
    unique\u ptr
    (和其他库类型)不会传播
    const
    ness(这就是我们添加的原因)

  • 下面的代码片段呢?它不会使用您建议的更改进行编译,而它是一个不应该被阻止的有效代码

  • class Base{virtual~Base()=default;};
    派生类:公共基{};
    空f(基&){}
    int main()
    {
    f(*std::make_unique());
    }
    
    (-如果我们的
    运算符*
    重载被注释掉,它将编译)



    请注意:我不确定
    auto&
    说“我是UB”的声音是否更大。相反,有些人认为,在许多情况下,
    auto&
    应该是我们的默认设置(例如,基于范围的for循环;甚至建议为“基于范围的for循环的简洁表示法”自动插入它(虽然不被接受,但仍然…)。让我们记住,rvalue ref与
    const&
    具有类似的效果,即延长临时变量的寿命(在已知的限制范围内),因此它通常不一定看起来像UB。

    原因:因为标准缺少r值ref限定重载
    运算符*
    。为什么没有添加ref限定版本?也许是一个疏忽,也许是一篇论文的好主意。当然,它必须是
    T&&operator*()&&{return::std::move(*ptr);}
    ,否则它甚至不会与您建议的更改一起编译,例如
    auto ptr=std::make_unique(7);auto&ref=*ptr仍然有效?”它更详细地说“我是UB”,因此没有那么重要:“我不明白为什么
    auto&
    并不意味着“我是UB”。@AmirKirsh:我的意思是它根本不是“说‘我是UB’”。即,它不是比ULVAIL参考版本更明确或明显的声明UB。因此,历史原因和一致性?这不是一个用例,更多的是“让我们保留一些UB也在智能指针中保持C++有趣”…这不是什么争论。我倾向于相信智能指针的设计是为了尽可能多地去除原始指针,而不是为了保存它们。@AmirKirsh:它不应该是一个“用例”。它应该回答你标题中的问题。它为什么这样做?因为智能指针应该尽可能像指针一样工作,指针就是这样工作的。“没什么好说的了。”尼古拉·博拉斯我同意。保留不良行为是没有意义的。最后的问题是:在std::unique_ptr的右值上有没有很好地使用操作符*返回左值ref?这两种说法是有区别的:它是出于历史原因而存在的,但可以改变;或者-这种行为有一个很好的用例,因此不能改变。@AmirKirsh:那么你的问题就无关紧要了。也许你会提出一个修改的建议,但它不会被接受,因为它是指针和智能指针之间不必要的区别,而且它不向后兼容。你需要比“我认为这不好”更重要的东西才能让委员会通过一个不向后兼容的变更。也就是说,它是否有“用例”并不重要,因为该行为不会有任何进展。这个更安全的替代方案存在我在回答中描述的问题,我已经删除了,因为它不适用于返回引用。问题是它引入了一个额外的复制/移动,这并不总是一个选项,特别是当元素类型不可复制且不可移动时。
    auto&& ref = *std::make_unique<int>(7);
    std::cout << ref << std::endl;
    
    auto &ref = *(new int(7));
    
    class Base { virtual ~Base() = default; };
    class Derived : public Base {};
    void f(Base&) {}
    
    int main()
    {
        f(*std::make_unique<Derived>());
    }