为什么static_cast可以编译将指针转换为智能指针

时间:2017-06-20 12:29:00

标签: c++ unique-ptr static-cast

我只是偶然发现了一个来自智能指针的强制转换,想要检查static_cast是否可以在编译时声明以下是无意义的:

int main()
{
    char foobar[4] = "Foo";
    std::unique_ptr<char[]> myptr = static_cast<decltype(myptr)>(foobar);
    myptr.reset();
    return 0;
}

这里发生的事情是myptr尝试释放foobar

我不是在问什么是智能指针或如何分配或以其他方式修复上述内容。

我认为这个问题应该在编译时捕获,因为这些类型应该是完全不兼容的。

为什么在编译时没有检测到这个?

2 个答案:

答案 0 :(得分:7)

The static_cast causes a call to the constructor of std::unique_ptr similar to what you can see in the following example

#include <iostream>
#include <memory>

using std::cout;
using std::endl;

class Something {
public:
    explicit Something(int) {
        cout << __PRETTY_FUNCTION__ << endl;
    }
};

int main() {
    auto something = static_cast<Something>(1);
    (void) something;
}

If you are wondering why the static_cast causes a call to the constructor of std::unique_ptr it can be explained with the following quote from the standard (emphasis mine)

Static cast [expr.static.cast/4]

An expression e can be explicitly converted to a type T using a static_cast of the form static_cast<T>(e) if the declaration T t(e); is well-formed, for some invented temporary variable t (8.5). The effect of such an explicit conversion is the same as performing the declaration and initialization and then using the temporary variable as the result of the conversion. The expression e is used as a glvalue if and only if the initialization uses it as a lvalue.

So basically in your example the array is treated as a parameter to the constructor of unique_ptr and then the imaginary temporary is then used to initialize the variable myptr (with elision in most cases)

The constructor that is called in your example is (2) in the following cppreference page http://en.cppreference.com/w/cpp/memory/unique_ptr/unique_ptr

explicit unique_ptr( pointer p ) noexcept;

Here you get a unique_ptr that points to the array.

Then when you call reset() the unique_ptr attempts to delete the variable with automatic lifetime and causes undefined behavior. This however is not required to be detected by the compiler.

答案 1 :(得分:4)

The code doesn't make sense but the syntax is valid, why wouldn't it be?

The static_cast here is basically the same as :

std::unique_ptr<char[]> myptr = std::unique_ptr<char[]>(foobar);

And even though that's nonsensical since you shouldn't hand a pointer that points to a variable with automatic lifetime it doesn't make the syntax invalid. The static_cast itself is perfectly fine.

The types aren't incompatible and there is no way for the compiler to check if the pointer handed to static_cast is pointing to dynamically allocated memory or not and thus it compiles fine. Of course, as you already stated, this is very much undefined behaviour and so the result of this program cannot be reasoned with, but that's not the compiler's job to warn the programmer about.