为什么对于MSVC12中的unique_ptr,is_copy_constructible返回true

Why does is_copy_constructible return true for unique_ptr in MSVC12

本文关键字:copy is constructible 返回 true ptr MSVC12 中的 unique 为什么      更新时间:2023-10-16

我本以为会触发这个静态断言:

#include <type_traits>
#include <memory>
int main() {
  static_assert(std::is_copy_constructible<std::unique_ptr<int>>::value, "UPtr has copy constructor?");
}

但事实并非如此。

使用MSVC12:编译

用于x64 的Microsoft(R)C/C++优化编译器18.00.31101版

static_assert应该激发,std::unique_ptr有一个隐式删除的复制构造函数,所以这是一个错误。这看起来与此错误报告有关std::is_copy_constructible已损坏:

(1) std::is_copy_constructible对于已删除的类型返回true复制构造函数。

(2) std::is_copy_constructible对于组成的类型返回true不可复制构造的类型。

结果是:

感谢您报告此错误。我们已经修复了它,该修复程序将在2013年之后的Visual Studio下一个主要版本中提供。

另外,请参阅此错误报告:std::is_copy_constructible无法正常工作。

请注意,断言在使用最新版本Visual Studio的Web编译器上激发。上次更新是在Dec 3, 2015上。断言还对clang(see it live)和gcc启动。

我发现了一个错误报告:std::is_copy_constructible的一个奇怪行为,它的代码与您的代码非常相似:

static_assert(std::is_copy_constructible<std::unique_ptr<int>>::value, "");

那里的反应是:

感谢您报告此错误。我们已经修复了,修复是在VS 2015预览版中提供。

目前还不清楚这是在Visual Studio的哪个版本中修复的。一个回复说是2013年末的版本,而后面的回复说是2015预览版。

以下是四种使类不可复制的方法:

#include <stdio.h>
#include <type_traits>
class A {
public:
    A(const A&) = delete;
    void operator=(const A&) = delete;
};
class B {
private:
    B(const B&) = delete;
    void operator=(const B&) = delete;
};
class C {
public:
    C(const C&) = delete;
    void operator=(const C&) = delete;
    void operator=(C) = delete;
};
class D {
private:
    D(const D&) = delete;
    void operator=(const D&) = delete;
    void operator=(D) = delete;
};
int main() {
    printf("%d %dn", std::is_copy_constructible<A>::value, std::is_copy_assignable<A>::value);
    printf("%d %dn", std::is_copy_constructible<B>::value, std::is_copy_assignable<B>::value);
    printf("%d %dn", std::is_copy_constructible<C>::value, std::is_copy_assignable<C>::value);
    printf("%d %dn", std::is_copy_constructible<D>::value, std::is_copy_assignable<D>::value);
}

在MSVC2013 x64(18.00.40629 for x64)上,它打印:

1 1    //A
0 1    //B
1 0    //C
0 0    //D

在正确的编译器上,所有八个值都必须为零。

不幸的是,这并不是提供一个很好的方法来解决MSVC2013中的错误,即使对于您自己的类也是如此。因为如果您通过值声明接受参数的赋值运算符,则不能在同一类中声明移动赋值(由于不明确的重载,任何移动赋值都不会编译)。

p.S.修正分配的关键思想取自这个相关答案。