C++中默认构造的对象返回和空括号返回有什么区别?

9
在以下代码中:
#include <memory>

struct A;

std::unique_ptr<A> ok() { return {}; }

std::unique_ptr<A> error() { return std::unique_ptr<A>{}; }

Clang++可以编译ok()函数,但会拒绝带有错误信息的error()函数:

In file included from /opt/compiler-explorer/gcc-11.1.0/lib/gcc/x86_64-linux-gnu/11.1.0/../../../../include/c++/11.1.0/memory:76:
/opt/compiler-explorer/gcc-11.1.0/lib/gcc/x86_64-linux-gnu/11.1.0/../../../../include/c++/11.1.0/bits/unique_ptr.h:83:16: error: invalid application of 'sizeof' to an incomplete type 'A'
        static_assert(sizeof(_Tp)>0,

Demo: https://gcc.godbolt.org/z/M8qofYbzn

C++中默认构造对象返回和使用空大括号返回之间是否存在任何真正的区别?(无论是一般情况还是在这个特定案例中)


3
我认为这可能是一个clang的bug,GCC和MSVC也无法编译这两个函数。 - Alan Birtles
有人能解释一下clang对ok的优化汇编是做了什么吗? mov rax, rdi; mov qword ptr [rdi], 0; ret 我怀疑是返回值优化,但不确定。 - Quimby
@Quimby 在 rdi 中,调用者将返回对象的存储地址传递给 ok 函数。ok 函数通过默认构造函数初始化该对象,该构造函数仅将其成员指针设置为 nullptr。这相当于通过 mov 指令将其二进制表示设置为零字节。最后,对象的地址在 rax 中返回。 - Daniel Langr
1
相同问题的更简单示例:https://godbolt.org/z/PWrvvGEbh。 - Daniel Langr
@DanielLangr 谢谢您的解释,我对汇编语言很糟糕。 - Quimby
1个回答

1

两者都不应该编译。

结果对象的析构函数始终可能被调用。对于unique_ptr,这要求A是完整的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接