为什么 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
会尝试删除具有自动生命周期的变量并导致未定义的行为。然而,编译器不需要检测到这一点。
我只是偶然发现了一个智能指针的强制转换,想检查一下 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 astatic_cast
of the formstatic_cast<T>(e)
if the declarationT t(e);
is well-formed, for some invented temporary variablet
(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 expressione
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
会尝试删除具有自动生命周期的变量并导致未定义的行为。然而,编译器不需要检测到这一点。