Why does is_copy_constructible return true for unique_ptr in MSVC12

只谈情不闲聊 提交于 2019-12-14 03:44:52

问题


I would have expected this static assertion to fire:

#include <type_traits>
#include <memory>

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

But it does not.

Compiled using MSVC12:

Microsoft (R) C/C++ Optimizing Compiler Version 18.00.31101 for x64


回答1:


The static_assert should fire, std::unique_ptr has an implicitly deleted copy constructor, so this is a bug. This looks related to this bug report std::is_copy_constructible is broken:

(1) std::is_copy_constructible returns true for types with deleted copy constructors.

(2) std::is_copy_constructible returns true for types that compose types that are not copy constructible.

and the response was:

Thanks for reporting this bug. We've fixed it, and the fix will be available in the next major version of Visual Studio after 2013.

Also, see this bug report: std::is_copy_constructible doesn't work correctly.

Note that the assert fires on webcompiler which is using an up to date version of Visual Studio. The last update was on Dec 3, 2015. The assert also fires on clang(see it live) and gcc.

I found a bug report: A strange behavior of std::is_copy_constructible which has very similar code to yours:

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

The response there is:

Thanks for reporting this bug. We've already fixed it, and the fix is available in VS 2015 Preview.

Not clear, what version of Visual Studio this is fixed in. One response says late 2013 version while the later on says 2015 Preview.




回答2:


Here are four ways to make class non-copyable:

#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);
}

On MSVC2013 x64 (18.00.40629 for x64), it prints:

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

On a proper compiler, all eight values must be zeroes.

Unfortunately, this does not provide a good way to workaround the bug in MSVC2013, even for your own classes. Because if you declare assignment operator accepting argument by value, then you cannot declare move assignment in the same class (any move assignment will not compile due to ambiguous overload).

P.S. The key idea for fixing assignment was taken from this related answer.



来源:https://stackoverflow.com/questions/34135409/why-does-is-copy-constructible-return-true-for-unique-ptr-in-msvc12

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!