Returning reference to locally dereferenced pointer - c++

Is the behavior of this code well-defined? Will the returned reference always be correct? Will the Bar::method() call always go well?
struct Bar
{
void method() {...};
};
struct Foo
{
static unique_ptr<Bar> bar_ptr;
static Bar& get_reference()
{
return *bar_ptr;
}
};
unique_ptr<Bar> Foo::bar_ptr = nullptr;
int main()
{
Foo::bar_ptr = make_unique<Bar>();
Foo::get_reference().method();
return 0;
}

Is the behavior of this code well-defined?
Yes it is.
The instance of struct Bar will go out of scope, thus destroyed, after main() terminates.

Related

Crash due to mixing CRTP & interfaces?

I am experimenting with CRTP and mixing it with interfaces, and I cannot explain why this program crashes (in Clang, GCC and MSVC). In latest Clang and GCC it builds without warning with -Wall, -Wextra. My guess is that the virtual method call is not resolved but I cannot explain why (no crash if GetInt() is removed from the interface). In my debugger I see that the crash happens on line static_cast<T*>(this)->GetInt().
#include <iostream>
class INode
{
public:
virtual int GetInt() = 0;
protected:
~INode() {}
};
template<template<class> typename NodeBase>
class Node : public INode, public NodeBase<Node<NodeBase>>
{
public:
int GetInt() override { return 42; }
};
template<typename T>
class MyNodeBase
{
public:
int CallGetInt() {
return static_cast<T*>(this)->GetInt();
}
};
template<template<class> typename NodeBase>
int Foo1(Node<NodeBase> n) {
return n.CallGetInt();
}
template<typename T>
int Foo2(MyNodeBase<T> n) {
return n.CallGetInt();
}
int main() {
Node<MyNodeBase> n;
std::cout << Foo1(n) << std::endl; // ok
std::cout << Foo2(n) << std::endl; // crash
}
You're slicing n in your call to Foo2.
Foo2 accepts its parameter by value. That means that a copy of n's MyNodeBase<Node<MyNodeBase>> sub-object is what gets passed to Foo2. Since n in Foo2 is not a Node<MyNodeBase>, calling GetInt through the pointer returned from the cast in CallGetInt results in your program exhibiting undefined behavior.
If you change Foo2 to accept its parameter by reference, you program's behavior would be well-defined.
Foo2 argument is passed by value. So the complete object n is of type MyNodeBase<Node<MyNodeBase>>. It is not a derived of Node<MyNodeBase>. But the expression static_cast<T*>(this) assumes that this is derived of Node<MyNodeBase> thus static_cast<T*>(this)->GetInt() is undefined behavior.
You avoid this error:
template<typename T>
class MyNodeBase
{
protected:
MyNodeBase() = default;
MyNodeBase(const MyNodeBase&) = default;
MyNodeBase& operator = (const MyNodeBase&) = default;
public:
int CallGetInt() {
return static_cast<T*>(this)->GetInt();
}
};

Is there a better/safe way to cast non-const reference of shared_ptr to a base class?

If you have a class Base with virtual methods and a class Implementation which implements the virtual methods, is there any way to cast std::shared_ptr < Implementation > & to std::shared < Base > &? The compiler allows this for const references, but for non const references it fails as in "Case A" in the code below. Is there an easy way to do this?
If not, how safe is my workaround "questionable_cast" in Case B?
#include <iostream>
#include <memory>
class Base
{
public:
virtual void set_value(int x) = 0;
};
class Implementation : public Base
{
public:
Implementation() : m_value(0) { }
void set_value(int x) override
{
m_value = x;
}
int get_value() const
{
return m_value;
}
private:
int m_value;
};
void do_something(std::shared_ptr<Base>& base)
{
base->set_value(5);
/// Code like this makes the non-const argument necessary
base = std::make_shared<Implementation>();
}
template <class T, class U>
std::shared_ptr<T>& questionable_cast(std::shared_ptr<U>& u)
{
/// This code is here to assure the cast is allowed
std::shared_ptr<T> tmp = u;
(void)tmp;
return *reinterpret_cast<std::shared_ptr<T>*>(&u);
}
int main()
{
std::shared_ptr<Implementation> a = std::make_shared<Implementation>();
// The following line causes a compiler error:
// invalid initialization of reference of type ‘std::shared_ptr<Base>&’ ...
// do_something(a);
// do_something(std::dynamic_pointer_cast<Base>(a));
// This is the workaround
do_something(questionable_cast<Base>(a));
std::cerr << "a = " << a->get_value() << std::endl;
return 0;
}
Two obvious solutions to the problem as originally asked: 1. Make do_something take a const reference to a shared_ptr (or a shared_ptr by value). 2. Create a named shared_ptr and pass a reference to that: Eg
int main()
{
std::shared_ptr<Implementation> a = std::make_shared<Implementation>();
std::shared_ptr<Base> b = a; // This conversion works.
do_something(b); // Pass a reference to b instead.
return 0;
}
Your questionable_cast function is a violation of the strict aliasing rules, and invokes undefined behaviour. It's quite likely to work in initial tests, and then a new release of the compiler will crank up the optimization a notch, and it will fail during a demo.
To handle the case where do_something changes the pointer:
int main()
{
std::shared_ptr<Implementation> a = std::make_shared<Implementation>();
std::shared_ptr<Base> b = a; // This conversion works.
do_something(b); // Pass a reference to b instead.
const auto aa = std::dynamic_pointer_cast<Implementation>(b);
if (aa)
a = aa;
else
; // Handle the error here
return 0;
}
If do_something guarantees to return a pointer of the same derived type, even if it doesn't return the same pointer, wrap it in a template function:
template <typename T>
void do_something_ex( std::shared_ptr<T>& a )
{
std::shared_ptr<Base> b = a;
do_something(b)
a = std::dynamic_pointer_cast<T>(b);
if (!a)
throw_or_assert;
}

Is this lvalue returning dangerous?

I have this code:
struct Base {};
struct Derived : public Base {
int somedata;
};
std::unique_ptr<Base> createTemporary() {
return std::make_unique<Derived>(); // This code has been simplified
}
template<typename T>
T& convertValueTo(std::unique_ptr<Base>&& obj) {
return static_cast<T&>(*obj);
}
int main() {
int data = convertValueTo<Derived>(createTemporary()).somedata;
return 0;
}
I designed the convertValueTo templated function to return the asked type of the object and mostly for function calls like
auto some_value = convertValueTo<Something_Else>(createTemporary()).a_member_variable;
Now I'm wondering.. is there a safer way to do this? If someone were to use the returned reference from convertValueTo, the temporary will be destroyed as soon as the line expression ends right?
My goal is:
Allow the use of a temporary and destroy it as soon as possible if the reference is not stored (as above)
Allow a safe reference binding to a valid object in case someone wants to
Convert to a unique_ptr of the required type. Then it is clear who has ownership of the dynamically created object, namely the unique_ptr returned from the conversion function. As soon as you create an lvalue reference to the dynamically created object, there will be the possibility that the reference survives the lifetime of your object.
#include <memory>
struct Base {};
struct Derived : public Base {
int somedata;
};
std::unique_ptr<Base> createTemporary() {
return std::make_unique<Derived>(); // This code has been simplified
}
template<typename T>
std::unique_ptr<T> convertValueTo(std::unique_ptr<Base>&& obj) {
auto ptr = obj.release ();
return std::unique_ptr<T> { static_cast<T*>(ptr) };
}
int main() {
int data = convertValueTo<Derived>(createTemporary())->somedata;
return 0;
}

static const int as map subscript

I ran into a strange issue.
Considering this example:
class Foo
{
static const int Bar = 5;
public:
Foo()
{
_map[Bar] = "some characters";
}
~Foo() {}
private:
std::map<int, std::string> _map;
};
int main()
{
Foo a;
return (0);
}
I get this error (compiling with g++ 4.7.2):
/tmp/ccLy806T.o: In function `Foo::Foo()':
Main.cpp:(.text._ZN3FooC2Ev[_ZN3FooC5Ev]+0x1e): undefined reference to `Foo::Bar'
Now, if I make a static_cast on Bar, it works:
Foo()
{
int i = Bar; //works
_map[static_cast<int>(Bar)] = "some characters"; //works
}
This error only appears when using Bar as map subscript in the constructor. Writing _map[Bar] = "some characters"; in an other function in the Foo class doesn't produce any error.
That's really strange for me, but I expect that someone here has an answer.
So, what am I doing wrong ?
That's because map::operator[] takes its key as a int const&. It wants the address of the thing you're passing into it. When you do:
_map[static_cast<int>(Bar)]
you're creating a temporary, and passing in the address to that temporary, which is fine. But when you're doing:
_map[Bar]
Bar doesn't actually have memory storage. You need to provide it via:
class Foo {
....
};
const int Foo::Bar;
You need to add the following at the top level to allocate storage for Foo::Bar:
const int Foo::Bar;

Is this valid C++ code according to standard?

I have this sample code:
struct A
{
bool test() const
{
return false;
}
};
template <typename T = A>
class Test
{
public:
Test(const T& t = T()) : t_(t){}
void f()
{
if(t_.test())
{
//Do something
}
}
private:
const T& t_;
};
int main()
{
Test<> a;
a.f();
}
Basically I am worried about the constructor of Test where I am storing a const reference to a temporary variable and using it in methof f. Will the temporary object reference remains valid inside f ?
It won't remain valid. The temporary object will be destroyed after initializing a. At the time you call f you invoke undefined behavior by calling test. Only the following is valid:
// Valid - both temporary objects are alive until after the
// full expression has been evaluated.
Test<>().f();