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

why can static_cast compile casting raw pointers to smart pointers

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

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

这里发生的是 myptr 试图释放 foobar

我不是在问什么是智能指针或如何分配或以其他方式解决上述问题。

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

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

代码没有意义,但语法有效,为什么不呢?

这里的static_cast和:

基本一样
std::unique_ptr<char[]> myptr = std::unique_ptr<char[]>(foobar);

尽管这是荒谬的,因为您不应该传递指向具有自动生命周期的变量的指针,但这并不会使语法无效。 static_cast 本身完全没问题。

类型不是不兼容的,编译器无法检查传递给 static_cast 的指针是否指向动态分配的内存,因此它可以正常编译。当然,正如您已经指出的那样,这是非常未定义的行为,因此无法推断出该程序的结果,但这不是编译器警告程序员的工作。

static_cast 导致调用 std::unique_ptr 的构造函数,类似于您在以下示例中看到的内容

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

如果您想知道为什么 static_cast 会导致调用 std::unique_ptr 的构造函数,可以用以下引用标准(强调我的)

来解释

静态转换 [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.

所以基本上在您的示例中,数组被视为 unique_ptr 的构造函数的参数,然后使用虚构的临时变量初始化变量 myptr (在大多数情况下使用省略)

您的示例中调用的构造函数是以下 cppreference 页面中的 (2) http://en.cppreference.com/w/cpp/memory/unique_ptr/unique_ptr

explicit unique_ptr( pointer p ) noexcept;

在这里你得到一个指向数组的unique_ptr

然后当您调用 reset() 时,unique_ptr 会尝试删除具有自动生命周期的变量并导致未定义的行为。然而,编译器不需要检测到这一点。