Is this valid C++ code according to standard? - c++

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();

Related

Is it possible to default-initialize a temporary variable?

Consider this code:
struct S { int m; };
S trick() { S s; return s; }
void bar(S s) { /* observe s.m */ }
void foo()
{
S s; // s.m is indeterminate
S* p = new S; // p->m is indeterminate
bar(S()); // bar() will observe S::m to be 0
bar(trick()); // bar() will observe S::m to be indeterminate
}
Is it possible to construct a temporary variable of type S without resorting to tricks?
Why do I need this?
As I understand "default initialization" is conceptually the cheapest way to construct an object. Ability to construct a temporary in such way can be useful to ignore data you don't need with as little of overhead as possible:
struct S { int m; };
void foo(S* pOut); // 3rd party function that insists on returning some data
template<class T> T* tmp_addr(T&& v) { return &v; } // careful with this one...
foo( tmp_addr(trick()) ); // receive and discard data without zeroing out memory
You can default initialize a sub-object of a temporary variable.
template<typename T>
class default_init_tmp final {
T t;
public:
default_init_tmp () /*Intentionally left blank*/ {}
default_init_tmp (default_init_tmp const&) = delete;
void operator=(default_init_tmp const&) = delete;
T* operator&() { return &t; }
};
Granted, usually it's ill-advised to overload operator&, but it somehow seems appropriate here, given the general nature of the exercise. You'd use it as follows
int main()
{
foo(&default_init_tmp<S>());
}
How about:
#include <memory>
struct Foo
{
int i;
};
auto trick() {
return std::make_unique_for_overwrite <Foo>(); // C++20
// return std::unique_ptr<Foo>(new Foo); // pre C++20
}
void foo(Foo* f);
int main()
{
foo(trick().get());
}
Is it possible to default-initialize a temporary variable?
I don't think so.
Also, the behaviour of your program is undefined, because it reads (copies) indeterminate values. A simple, and correct way to use foo without value initialisation is to not use a temporary:
S s;
foo(&s);

Returning reference to locally dereferenced pointer

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.

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;
}

Passing a pointer to temporary object

We know that we can pass temporary objects to functions by const reference, like this:
class A
{
public:
A(int _b = 0)
{
b = _b;
}
int b;
};
void foo(A& a) {printf("%d", a.b);}
void cfoo(const A& a) {printf("%d", a.b);}
int main(void)
{
//foo(A(4)); doesn't compile
cfoo(A(5));
}
but what about passing by pointer?
why does this compile?
void pfoo(A* pa) {pa->b = 19;}
int main(void)
{
pfoo(&A(5));
}
but what about passing anonymous variables pointer? why does this compile?
You are probably using a compiler that does not honour C++ standard.
No address of an r-value (temporary) object can be taken. That should not compile.
However, operator& can be overloaded, so that it can be invoked on a temporary object, e.g.:
struct A
{
A* operator&() { return this; }
};
In C++11 a temporary object can be bound to an r-value reference. After that r-value reference behaves like an l-value and hence the address of a temporary object can be taken:
struct A {};
void foo(A*);
void foo(A&& a) { foo(&a); }
int main() {
foo(A{});
}