I just stumbled into a cast from a smart pointer and wanted to check if static_cast could assert at compile time that the following is nonsensical:
int main()
{
char foobar[4] = "Foo";
std::unique_ptr<char[]> myptr = static_cast<decltype(myptr)>(foobar);
myptr.reset();
return 0;
}
What happens here is that myptr attempts to free foobar.
I am not asking what a smart pointer is or how to allocate or otherwise fix the above.
I thought this problem should be caught at compile time, since these types should be completely incompatible.
Why is this not detected at compile time?
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
Tusing astatic_castof 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 expressioneis 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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With