多态性unique_ptr复制省略

polymorphic unique_ptr copy elision

本文关键字:复制省 ptr unique 多态性      更新时间:2023-10-16

我有以下代码适用于 Clang 5.0,但不适用于 Clang 3.8,启用了 C++14:

class Base {};
class Derived : public Base {};
std::unique_ptr<Base> MakeDerived()
{
auto derived = std::make_unique<Derived>();
return derived;
}
int main()
{
auto base = MakeDerived();
std::cout << "Type: " << typeid(base).name() << 'n';
}

现场样品在这里

在这种情况下,由于复制省略,返回值在技术上是否被移动构造?如果是这样,这是否意味着unique_ptr的移动构造函数旨在支持用户类类型的隐式向上转换?很难从 cppreference 文档 中分辨出来,除非我应该在该文档页面上假设模板类型U与类本身的类型T明显不同。

很明显这有效的一件事是unique_ptr不是可复制可构造的,并且由于我不通过std::move()将其转换为右值,因此除了复制 elision 之外,没有其他解释可以解释为什么代码会编译。但是,因为它不适用于接受-std=c++14标志的 clang 3.8,我想确保标准本身保证在某个地方(如果是这样,在哪里),这只是编译器错误或缺乏支持 问题在 Clang 的 v3.8 中。

Copy elision(在 C++17 之前)总是要求 elided 构造函数是实际可访问的,因此它不能成为代码工作的原因。

但是请注意,C++(自 C++11 起)有一条规则 (12.8/32),该规则归结为以下内容:"返回对象时,在某些情况下首先尝试将对象视为右值,只有当失败时,才将其视为左值。

在 C++11 中,这些"某些情况"是"复制省略是可能的",这要求返回对象和返回类型是相同的类型(模 cv 限定)。

在C++14中,这些"某些情况"被放宽为"复制省略是可能的,或者返回的对象是函数中的局部变量"。

因此,在 C++11 中,代码失败,因为std::unique_ptr<Derived>(derived的类型)与std::unique_ptr<Base>(返回类型)不同,因此必须使用std::move

在 C++14 中,代码成功,因为derived是函数中的局部,因此首先被视为右值。这使得你引用的构造函数模板适用:

如果std::unique_ptr<T>可以转换为T*,则可以从std::unique_ptr<U>类型的右值构造U*

您的 Clang 3.8 似乎表现出 C++11 行为;也许它尚未(尚未/完全)在该版本中实现 C++14 的宽松方面。


(是的,实际上您应该假设"模板类型"U与类的模板参数T不同。这就是首先引入它的原因:#6 描述的构造函数是一个构造函数模板)。

return调用unique_ptr的转换移动构造函数模板,template<class U, class E> unique_ptr(unique_ptr<U, E>&&)。没有省略;它取决于核心问题 1579 的解决方案所启用的隐式移动derived