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;
}
Related
Example code:
#include <iostream>
using namespace std;
struct Data {
int d;
};
class Foo {
public:
explicit Foo(const Data& data) : data_(data) {}
void PrintData() {
std::cout << data_.d << std::endl;
}
private:
const Data& data_;
};
Foo CreateFoo(int i) {
Data d;
d.d = i;
return Foo(d);
}
int main() {
Foo foo = CreateFoo(5);
foo.PrintData(); // prints 0 instead of 5
return 0;
}
https://ideone.com/KpCstl
foo.data_ is a reference to the Data created in CreateFoo which goes out of scope at the end of the function.
Without changing the definition of class Foo (e.g. to remove the reference), how can I extend the lifetime of d/data_, preferably so that it matches the lifetime of the Foo instance?
Is there perhaps some container object that I can wrap Foo in that will keep all its deps alive and return that from CreateFoo instead?
In the actual usage, our framework will keep Data alive, so it will outlive Foo as intended. But for my test code, I need to find another mechanism to keep Data alive at least until the test run is complete. I can use some kind of singleton to keep it alive, but I'm looking for a cleaner solution.
If you want to keep the reference in the member variable, then likely you will need to use dynamic allocation. Think about it -- the reference must point to some Data object somewhere that has the same lifetime as the Foo, but the Data object can't be stored with the Foo object, as the Foo object has no space for it, only for a reference. So generally in this case it is allocated on the heap. I would suggest using a unique_ptr to automatically manage this Data object:
#include <iostream>
#include <memory>
using namespace std;
struct Data {
int d;
};
class Foo {
public:
explicit Foo(const Data& data) : data_(std::make_unique<Data>(data)) {}
void PrintData() {
std::cout << data_->d << std::endl;
}
private:
std::unique_ptr<Data> data_;
};
Foo CreateFoo(int i) {
Data d;
d.d = i;
return Foo(d);
}
int main() {
Foo foo = CreateFoo(5);
foo.PrintData();
return 0;
}
Note that a unique_ptr allows only for one object to have ownership, which will disallow Foos from being copied unless you override the relevant methods. If you want copied Foos to have references to the same object, use shared_ptr and make_shared instead. If you want copied Foos to copy their Data objects, overload the copy constructor and operator=, or better yet, turn the Data pointer into a plain Data member.
If you don't want to have Foos own and manage their Datas, then I would suggest:
#include <iostream>
#include <memory>
using namespace std;
struct Data {
int d;
};
class Foo {
public:
explicit Foo(Data& data) : data_(data) {}
void PrintData() {
std::cout << data_->d << std::endl;
}
private:
Data& data_;
};
struct FooWithData {
Data foo_data;
Foo foo;
FooWithData(const FooWithData& other)
: foo_data(other.foo_data),
foo(foo_data) {}
FooWithData(FooWithData&& other)
: foo_data(other.foo_data),
foo(foo_data) {}
FooWithData& operator=(FooWithData& other) {
foo_data = other.foo_data;
}
};
FooWithData CreateFoo(int i) {
FooWithData ret;
ret.foo_data = Data { i };
ret.foo = Foo(ret.foo_data);
return ret;
}
int main() {
FooWithData foo_compound = CreateFoo(5);
foo_compound.foo.PrintData();
return 0;
}
This solution should work for you:
Foo CreateFoo(int i) {
static std::forward_list<Data> v;
v.push_front(Data{i});
return Foo(v.front());
}
Maintain a static container of Data objects, add a new object on every call to CreateFoo, and hand out references to the last inserted object.
Since the container is static you won't have lifetime issues. Also, a container of objects ensures that every call returns a Foo that binds to a unique Data object.
Also, note that you need a container that doesn't invalidate references to it on modification, so I chose std::forward_list.
Here's a demo.
If you want to keep your element alive even after scopes ends then you should use pointer, but again raw pointer is dangerous, so to counter this use std::shared_ptr, but then you wont be able to use ref variable to shared_ptr but an actual shared_ptr variable to keep the object of Data alive.
struct Data{
int data;
};
class Foo{
public:
explicit Foo(std:shared_ptr<Data>) {data = _data;}
Foo createFoo(){
shared_ptr<Data> d(new Data);
return Foo(d);//this thing makes sure your shared pointer gets copied and it does not go out of scope
}
std::shared_ptr<Data> data;
};
I have the following code: (live on Coliru)
#include <iostream>
class ClassA{
public:
ClassA(int i) : m_int(i){};
int m_int;
};
class Master{
public:
Master(){};
~Master(){
delete m_classMain;
}
ClassA* m_classMain;
template<typename T>
void mem(T* t, int i){
t = new T(i);
}
void test() {
mem(m_classMain,3);
}
int get_i() const{
return m_classMain->m_int;
}
};
int main()
{
Master* master = new Master();
master->test();
std::cout << master->get_i() << std::endl;
delete master;
}
I would like to initialize the object ClassA* m_classMain through the method mem(T* t, int i) which is a template method.
For some reason I only get a segmentation fault. I think t = new T(i) might be the problem here, but I can not figure why (unfortunately I do not have a debugger at hand).
In your posted code, the member variable m_classMain is not initialized. Calling delete on it is cause for undefined behavior.
The call
mem(m_classMain,3);
does not initialize m_classMain since you are passing it by value. To initialize it in mem, you'll have to pass it by reference.
template<typename T>
void mem(T*& t, int i){ //T*& t, not T* t.
t = new T(i);
}
As a matter of good coding practice, make sure that all member variables are initialized in the constructor(s).
Master() : m_classMain(nullptr) {};
You are passing the t parameter of the mem() function by value. It gets destroyed on function exit. Consider passing by reference, or accessing the member directly from the member function.
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.
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;
}
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();