我只是偶然发现了一个来自智能指针的强制转换,想要检查static_cast
是否可以在编译时声明以下是无意义的:
int main()
{
char foobar[4] = "Foo";
std::unique_ptr<char[]> myptr = static_cast<decltype(myptr)>(foobar);
myptr.reset();
return 0;
}
这里发生的事情是myptr
尝试释放foobar
。
我不是在问什么是智能指针或如何分配或以其他方式修复上述内容。
我认为这个问题应该在编译时捕获,因为这些类型应该是完全不兼容的。
为什么在编译时没有检测到这个?
答案 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 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.
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.