【问题标题】:Why does is_copy_constructible return true for unique_ptr in MSVC12为什么 is_copy_constructible 在 MSVC12 中为 unique_ptr 返回 true
【发布时间】:2018-03-04 21:01:01
【问题描述】:

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

#include <type_traits>
#include <memory>

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

但事实并非如此。

使用 MSVC12 编译:

Microsoft (R) C/C++ 优化编译器版本 18.00.31101 for x64

【问题讨论】:

  • 奇数。在 GCC 5 (Linux) 上,断言触发。
  • 在webcompiler 上失败,据我所知这是相对最新的视觉工作室。
  • 很公平,那只是我们版本上的一个编译器错误!不幸的是,我们不能只升级。很容易解决,但看起来很奇怪。
  • @RichardHodges 我喜欢我工作的地方,谢谢。在侮辱他人的工作场所之前,请考虑一下现在不升级的充分理由。

标签: c++ c++11 typetraits msvc12


【解决方案1】:

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

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

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

得到的回应是:

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

另外,请参阅此错误报告:std::is_copy_constructible doesn't work correctly。

请注意,断言在 webcompiler 上触发,它使用的是最新版本的 Visual Studio。最后一次更新是在Dec 3, 2015。该断言还会在 clang(see it live) 和 gcc 上触发。

我发现了一个错误报告:A strange behavior of std::is_copy_constructible 与您的代码非常相似:

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

那里的回应是:

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

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

【讨论】:

  • 不知道那个网络编译器。将是一个方便的工具谢谢。
  • "std::unique_ptr 既不是 CopyConstructible 也不是 CopyAssignable" - 我们不要将 CopyConstructible 和 CopyAssignable(概念)与 is_copy_constructible 等检查混淆。前者比后者强很多。
  • @T.C.我知道这可能会令人困惑,已修复。
【解决方案2】:

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

#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 %d\n", std::is_copy_constructible<A>::value, std::is_copy_assignable<A>::value);
    printf("%d %d\n", std::is_copy_constructible<B>::value, std::is_copy_assignable<B>::value);
    printf("%d %d\n", std::is_copy_constructible<C>::value, std::is_copy_assignable<C>::value);
    printf("%d %d\n", 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. 修复分配的关键思想来自this related answer。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-29
    • 1970-01-01
    • 1970-01-01
    • 2019-12-07
    • 2021-11-10
    • 2010-09-13
    • 2017-05-03
    相关资源
    最近更新 更多