Bullet-proofing C++ temporary lifetimes? - c++

Revisiting lifetime extension in C++, I found out that there are some patterns that break "decomposability" of C++ expressions. For example, the following two blocks are a valid C++ code:
class NonMovable {
public:
NonMovable(NonMovable&&) = delete;
NonMovable(const NonMovable&) = delete;
NonMovable();
int Value() const;
};
template <class T>
const T& identity(const T& x) {
return x;
}
template <class T>
class A {
public:
explicit A(const T& value) : value_(value) {}
const T& GetValue() const {
return value_;
}
private:
const T& value_;
};
Correct usage:
int main() {
int retcode = identity(
identity(/*tmp1*/ A(/*tmp2*/ NonMovable{}).GetValue())).Value();
// tmp1 and tmp2 end their lifetimes here:
// their full-expression is the whole previous line
return retcode;
}
But if we decompose the first expression in main, it becomes invalid:
int main() {
auto&& a_obj = /*tmp1*/ A(/*tmp2*/ NonMovable{});
// tmp2 lifetime ends here
// oops! dereferencing dangling reference:
int retcode = identity(
identity(a_obj.GetValue())).Value();
return retcode;
// tmp1 lifetime ends here
}
My question is:
Is it possible to disable the second kind of usage?
P.S.: I'm not really sure if the second main introduces UB, because I've tested it with clang -Wlifetime, and it doesn't complain. But I still believe it is UB. In real life I've came across a similar behaviour: the code broke, emmiting UBSan warnings and segfaults if I decomposed a single expression into two separate ones.
P.P.S.: those identitys don't really matter much, if I understand object lifetimes correctly (which I now doubt)

Your analysis is correct. Without lifetime extension, all temporaries are destroyed at the end of the "full expression", i.e. the ; at the end of the line. So when you say
int retcode = A(NonMovable{}).GetValue().Value();
(comments and identity calls removed for clarity) then everything is okay; the NonMovable object is still alive at the time you ask for its value.
On the other hand, when you say
auto&& a_obj = A(NonMovable{});
then the NonMovable is destroyed at the end of the line, and the A object will be holding a dangling reference. (As an aside, auto&& just lifetime-extends the temporary A here -- you may as well just use plain auto)
My question is: Is it possible to disable the second kind of usage?
Not really, at least as far as I know. You could add a deleted A(NonMovable&&) constructor, but this would also prevent "correct" usage as in the first example. The is exactly the same issue that occurs with std::string_view (and will occur with std::span in C++20) -- essentially, your A class has reference semantics, but is referring to a temporary which has been destroyed.

So by using collective mind, in the comments under the question we've managed to come up with the following implementation of A, which might be applicable to some use cases (but not std::span or std::string_view usage):
struct Dummy;
template <class T>
class A {
public:
explicit A(const T& value) : value_(value) {}
template <class TDummy = Dummy>
const T& GetValue() const& {
static_assert(!std::is_same_v<TDummy, Dummy>,
"Stop and think, you're doing something wrong!"
"And in any case, don't use std::move on this class!");
}
const T& GetValue() && {
return value_;
}
private:
const T& value_;
};
Now, if one tries to compile the following code, he will get a descriprive error message:
int main() {
auto&& a_obj = A(NonMovable{});
// will not compile:
int retcode = identity(
identity(a_obj.GetValue())).Value();
return retcode;
}
The reason is that decltype((a_obj)) == A<NonMovable>&, so it binds to the method that produces a compile time error.
It satisfies my use cases, but, sadly, this is not a universal solution -- it depends on what one wants from class A.

Related

Is it possible to deserialize (from raw memory block) an object with no default constructor?

I was writing this little tool that helps avoid strict aliasing violations:
template <typename TargetType>
TargetType memory_cast(const void* const memoryPtr) noexcept
{
static_assert(!std::is_reference_v<TargetType>);
static_assert(std::is_trivially_copy_assignable_v<TargetType>);
TargetType value;
::memcpy(&value, memoryPtr, sizeof(value));
return value;
}
And it occurred to me that it will fail if TargetType is not default-constructible, but technically speaking that shouldn't matter because we already have a fully constructed data of the object, just no object instance itself to put the data in. Is there a way to solve this problem in modern C++ without invoking UB?
Before std::bit_cast in C++20, it's not really possible to do what you're suggesting, within the confines of the C++ standard. Trivial copyability (not the same thing as is_trivially_copy_assignable_v, BTW) permits byte copying between the object representation of live instances of such a type (potentially using an intermediary buffer between them). But you still need a live instance to copy into.
Indeed, this is a big part of why bit_cast was added to C++20.
I would just pass this problem down to whoever is calling the function:
#include <cstring>
#include <type_traits>
#include <memory>
template <typename TargetType>
void memory_cast(TargetType& to, const void* const memoryPtr) noexcept
{
static_assert(std::is_trivially_copyable_v<std::remove_reference_t<TargetType>>);
std::memcpy(std::addressof(to), memoryPtr, sizeof(to));
}
template <typename TargetType>
TargetType memory_cast(const void* const memoryPtr) noexcept
{
static_assert(!std::is_reference_v<TargetType>);
static_assert(std::is_trivially_copyable_v<TargetType>);
TargetType value;
memory_cast(value, memoryPtr);
return value;
}
Since the object has to start it's lifetime somewhere, and if it can't be default constructed, there is probably still some way to create it specific to the type (That can be done by the calling code).
Proposal p0593r2 would give a new way to do this without breaking strict-aliasing (As std::memcpy would now also start the lifetime of an object):
template <typename TargetType>
TargetType memory_cast(const void* const memoryPtr) noexcept
{
static_assert(!std::is_reference_v<TargetType>);
static_assert(std::is_trivially_copyable_v<TargetType>);
alignas(TargetType) std::byte value[sizeof(TargetType)];
std::memcpy(value, memoryPtr, sizeof(TargetType));
return *reinterpret_cast<TargetType*>(value);
}
We can add a default parameter that allows us to specify the initial state of the object:
template<class TargetType>
constexpr auto get_default = []{ return TargetType{}; };
template <typename TargetType, class Initial = decltype(get_default<TargetType>)>
TargetType memory_cast(
const void* const memoryPtr,
Initial initial = get_default<TargetType>) noexcept
{
static_assert(!std::is_reference_v<TargetType>);
static_assert(std::is_trivially_copy_assignable_v<TargetType>);
TargetType value = initial();
::memcpy(&value, memoryPtr, sizeof(value));
return value;
}
Handling default-constructible types. Because the second parameter is defaulted, the interface remains exactly the same:
char data[] = "abcd";
int value = memory_cast<int>(data); // default-constructs int, then assigns it from data
Handling types without a default constructor: Let's say we have a type without a default constructor:
struct Foo {
int x, y, z;
Foo() = delete;
Foo(int x, int y, int z)
: x(x), y(y), z(z) {}
Foo(const Foo& foo) = default;
Foo& operator=(Foo const& foo) = default;
};
We can provide the second parameter as a lambda:
char data[] = "abcdefghijkl";
Foo f = memory_cast<Foo>(data, []() { return Foo(0, 0, 0); });

Are references helpful when operating in a constexpr/compile-time context only?

I am exploring the world of constexpr and have decided to create a class that should only be used in constexpr context and other compile-time constructs.
Usually, I take great care to provide all necessary overloads a class may need, for example:
template <typename T>
struct Thing
{
Thing(T value) : m_value(value) {}
T &value() & { return m_value; }
const T &value() const & { return m_value; }
T &&value() && { return std::move(m_value); }
private:
T m_value;
};
The set of overloads for Thing::value should take care of efficient access to the stored value, no unnecessary copies are made. If the Thing instance is a temporary, the stored value can even be moved out.
But what if Thing is only to be used as a constexpr type, are all these different overloads for Thing::value required or even helpful at all? Or would the following be equivalent:
template <typename T>
struct Thing
{
constexpr Thing(T value) : m_value(value) {}
constexpr T value() const;
private:
T m_value;
};
My question basically boils down to: are references helpful (more efficient) when operating in a constexpr/compile-time context only; or is passing everything by value equivalent?
My question basically boils down to: are references helpful (more efficient) when operating in a constexpr/compile-time context only; or is passing everything by value equivalent?
It's a matter of what's your actual problem and how you plan to solve it. In most of the cases (all of them?) you won't need to use references in such a context, I agree, but you can still use them if required.
Here as a minimal, working example:
const int i = 0;
template <typename T>
struct Thing {
constexpr Thing(const T &value) : m_value(value) {}
constexpr const T & value() const { return m_value; }
private:
const T & m_value;
};
int main() {
static_assert(Thing<int>{i}.value() == 0, "!");
}
See it up and running on wandbox.
So, are references helpful (more efficient) in this case? Well, it's not a matter of efficiency or whatever. To use references in such a context you have to have a good reason and the language sets a lot of limitations. They solve a specific problem, it's not your taste to decide to use references.
If your problem requires you to use references, they are there for you (and please, contact me - I'm just curious to know what's that problem!). Otherwise feel free to keep on with passing by value.

Detect dangling references to temporary

Clang 3.9 extremely reuses memory used by temporaries.
This code is UB (simplified code):
template <class T>
class my_optional
{
public:
bool has{ false };
T value;
const T& get_or_default(const T& def)
{
return has ? value : def;
}
};
void use(const std::string& s)
{
// ...
}
int main()
{
my_optional<std::string> m;
// ...
const std::string& s = m.get_or_default("default value");
use(s); // s is dangling if default returned
}
We have tons of code something like above (my_optional is just a simple example to illustrate it).
Because of UB all clang compiler since 3.9 starts to reuse this memory, and it is lawful behavior.
The question is: how to detect such dangling references at compile time or with something like sanitizer at runtime? No clang sanitizer can detect them.
Upd. Please do not answer: "use std::optional". Read carefully: question is NOT about it.
Upd2. Please do not answer: "your code design is bad". Read carefully: question is NOT about code design.
You can detect misuses of this particular API by adding an additional overload:
const T& get_or_default(T&& rvalue) = delete;
If the argument given to get_or_default is a true rvalue, it will be chosen instead, so compilation will fail.
As for detecting such errors at runtime, try using Clang's AddressSanitizer with use-after-return (ASAN_OPTIONS=detect_stack_use_after_return=1) and/or use-after-scope (-fsanitize-address-use-after-scope) detection enabled.
You could try out lvalue_ref wrapper from Explicit library. It prevents the unwanted binding to a temporary in one declaration, like:
const T& get_or_default(lvalue_ref<const T> def)
{
return has ? value : def.get();
}
That is an interesting question. The actual cause of the dangling ref is that you use an rvalue reference as if it was an lvalue one.
If you have not too much of that code, you can try to throw an exception that way:
class my_optional
{
public:
bool has{ false };
T value;
const T& get_or_default(const T&& def)
{
throw std::invalid_argument("Received a rvalue");
}
const T& get_or_default(const T& def)
{
return has ? value : def;
}
};
That way, if you pass it a ref to a temporary (which is indeed an rvalue), you will get an exception, that you will be able to catch or at least will give a soon abort.
Alternatively, you could try a simple fix by forcing to return a temporary value (and not a ref) if you were passed an rvalue:
class my_optional
{
public:
bool has{ false };
T value;
const T get_or_default(const T&& def)
{
return get_or_default(static_cast<const T&>(def));
}
const T& get_or_default(const T& def)
{
return has ? value : def;
}
};
Another possibility would be to hack the Clang compiler to ask it to detect whether the method is passed an lvalue or an rvalue, by I am not enough used to those techniques...

Is there any obvious drawback to use a no assignment swap?

I was implementing (for training purpose) a Bubble Sort template function:
template<typename iterInput,
typename predicate>
void BubbleSort(iterInput first1,iterInput last1,predicate func)
{
bool swapped(false);
do
{
swapped = false;
iterInput begin = first1;
iterInput beginMinus = first1;
++begin;
for (;begin != last1; begin++,beginMinus++)
{
if (func(*beginMinus,*begin) )
{
std::swap(*beginMinus,*begin);
swapped = true;
}
}
}
while(swapped);
}
When I have realized that this function will not work for class with no assignment operator, like this one (forgive me for the bad name):
class NoCopyable
{
public:
explicit NoCopyable(int value) : value_(value) {}
NoCopyable(const NoCopyable& other) : value_(other.value_) {}
~NoCopyable() {}
bool operator<(const NoCopyable& other) { return value_ < other.value_; }
void setValue(int value) { value_ = value; }
std::ostream& print(std::ostream& os) const { return os << value_; }
private:
NoCopyable& operator=(const NoCopyable& other);
int value_;
};
std::ostream& operator<<(std::ostream& os, const NoCopyable& obj)
{
return obj.print(os);
}
struct PrintNoCopyable
{
void operator()(const NoCopyable& noCopyable) { std::cout << noCopyable << '\n'; }
};
The compiler raises this error Error 1 error C2248: 'NoCopyable::operator =' : cannot access private member declared in class 'NoCopyable'
So, I have slightly modify the code using instead of the std::swap function my version of the swap function, here is the code:
template<typename T1,
typename T2>
void noAssignmentSwap(T1& t1,T2& t2)
{
T1 temp(t1);
t1.~T1();
new (&t1) T1(t2);
t2.~T2();
new (&t2) T2(temp);
}
The code compiles and gives the right result. However I am not completely sure, I remember a Sutter's article that suggest you to avoid playing with the objects life time. The article just warns you by playing with fire without actually giving you any real reason. I can see problem in exception safety if the copy constructor of T1 or T2 can throw. However there is the same problem in the standard version if the assignment operator is allowed to throw.
Here the question, can you see any possible drawbacks in this version of swap?
Cheers
Apart from anything else, if a class does not have an assignment operator, its designer probably did not intend it to be swapped. If they did that, they probably disabled copy construction too, so your new swap function still won't work.
As for your assertion that Standard Library containers do not need assignment - that is true so long as you don't want to actually do anything useful with them. Does this code compile for you?
#include <vector>
using namespace std;
struct A {
private:
void operator=( const A &);
};
int main() {
vector <A> v;
v.push_back( A() );
v[0] = A(); // assignment needed here
}
I think it won't.
The difference is that when the assignment operator fails, you still have the same number of objects.
If you destroy one object and fail to create a new one, one object is lost! If it was part of a container, the container's state is probably also invalid.
You need a copy ctor instead of an assignment operator, but the two are sufficiently similar that at least in a typical case, you'll have both or you'll have neither. IOW, I don't think this generally accomplishes much.
I'd class it right along side the xor-swap trick: interesting, but generally useless.
It might be confusing to a future maintainer of the code.

const and pointers

Edit1: I realize this is hard to understand this question without having an insight of what I'm trying to do. The class A is not complete but it essentially stand for a C-array "proxy" (or "viewer" or "sampler"). One interesting usage is too present a C-array as a 2d grid (the relevant function are not shown here). The property of this class are the following:
it should not own the data - no deep copyy
it should be copyable/assignable
it should be lightweight (
it should preserve constness (I'm having trouble with this one)
Please do not question the purpose or the design: they are the hypothesis of the question.
First some code:
class A
{
private:
float* m_pt;
public:
A(float* pt)
:m_pt(pt)
{}
const float* get() const
{
return m_pt;
}
void set(float pt)
{
*m_pt = pt;
}
};
void gfi()
{
float value = 1.0f;
const A ac(&value);
std::cout<<(*ac.get())<<std::endl;
A a = ac;
a.set(2.0f);
std::cout<<(*ac.get())<<std::endl;
}
Calling "gfi" generate the following output:
1
2
Assigning a with ac is a cheap way to shortcut the constness of ac.
Is there a better way to protect the value which m_pt point at?
Note that I DO want my class to be copyable/assignable, I just don't want it to loose its constness in the process.
Edit0: I also DO want to have a pointer in there, and no deep copy please (let say the pointer can be a gigantic array).
Edit2: thanks to the answers, I came to the conclusion that a "const constructor" would be a useful thing to have (at least in this context). I looked it up and of course I'm not the same one who reached this conclusion. Here's an interesting discussion:
http://www.rhinocerus.net/forum/language-c-moderated/569757-const-constructor.html
Edit3: Finally got something which I'm happy with. Thanks for your help. Further feedback is more than welcome
template<typename T>
class proxy
{
public:
typedef T elem_t;
typedef typename boost::remove_const<T>::type elem_unconst_t;
typedef typename boost::add_const<T>::type elem_const_t;
public:
elem_t* m_data;
public:
proxy(elem_t* data = 0)
:m_data(data)
{}
operator proxy<elem_const_t>()
{
return proxy<elem_const_t>(m_data);
}
}; // end of class proxy
void test()
{
int i = 3;
proxy<int> a(&i);
proxy<int> b(&i);
proxy<const int> ac(&i);
proxy<const int> bc(&i);
proxy<const int> cc = a;
a=b;
ac=bc;
ac=a;
//a=ac; // error C2679: binary '=' : no operator found which takes a right-hand operand of type...
//ac.m_data[0]=2; // error C3892: 'ac' : you cannot assign to a variable that is const
a.m_data[0]=2;
}
Your class is badly designed:
it should use float values, not pointers
if you want to use pointers, you probably need to allocate them dynamically
and then you need to give your class a copy constructor and assignment operator (and a destructor) , which will solve the problem
Alternatively, you should prevent copying and assignment by making the copy constructor and assignment op private and then not implementing them.
You can trick around with proxy pattern and additional run-time constness boolean member. But first, please tell us why.
Effectively your class is like an iterator that can only see one value. It does not encapsulate your data just points to it.
The problem you are facing has been solved for iterators you should read some documentation on creating your own iterator and const_iterator pairs to see how to do this.
Note: in general a const iterator is an iterator that cannot be incremented/decremented but can change the value it points to. Where as a const_iterator is a different class that can be incremented/decremented but the value it points to cannot be changed.
This is the same as the difference between const float * and float *const. In your case A is the same as float * and const A is the same as float *const.
To me your choices seem to be:
Encapsulate your data.
Create a separate const_A class like iterators do
Create your own copy constructor that does not allow copies of const A eg with a signature of A(A & a);
EDIT: considering this question some more, I think you are misinterpreting the effect of const-correctness on member pointers. Consider the following surprising example:
//--------------------------------------------------------------------------------
class CNotSoConstPointer
{
float *mp_value;
public:
CNotSoConstPointer(float *ip_value) : mp_value(ip_value) {}
void ModifyWithConst(float i_value) const
{
mp_value[0] = i_value;
}
float GetValue() const
{
return mp_value[0];
}
};
//--------------------------------------------------------------------------------
int _tmain(int argc, _TCHAR* argv[])
{
float value = 12;
const CNotSoConstPointer b(&value);
std::cout << b.GetValue() << std::endl;
b.ModifyWithConst(15);
std::cout << b.GetValue() << std::endl;
while(!_kbhit()) {}
return 0;
}
This will output 12 and then 15, without ever being "clever" about the const-correctness of the const not-so-const object. The reason is that only the pointer ITSELF is const, not the memory it points to.
If the latter is what you want, you'll need a lot more wrapping to get the behavior you want, like in my original suggestion below or Iain suggestion.
ORIGINAL ANSWER:
You could create a template for your array-proxy, specialized on const-arrays for the const version. The specialized version would have a const *m_pt, return a const pointer, throw an error when you try to set, and so on.
Edit: Something like this:
template<typename T>
class TProxy
{
T m_value;
public:
TProxy(T i_t) : m_value(i_t) {};
template<typename T>
TProxy(const TProxy<T> &i_rhs) : m_value(i_rhs.m_value) {}
T get() { return m_value; }
void set(T i_t) { m_value = i_t; }
};
template<typename T>
class TProxy<const T *>
{
const T *mp_value;
public:
TProxy(const T *ip_t) : mp_value(ip_t) {};
template<typename T>
TProxy(const TProxy<T> &i_rhs) : m_value(i_rhs.mp_value) {}
T get() { return m_value; }
};
Why not replace float* with float in A. If you don't either the original owner of the float that the float* references can change it, or anyone prepared to do a mutable cast on the return value from a::get.
const is always just a hint to the compiler; there are no ways to make a variable permanently read-only.
I think you should use deep copy and define your own assingment operator and copy constructor.
Also to return handle to internal data structure in not a good practice.
You can deny the copy-constructor for certain combinations of arguments:
For instance, adding the constructor;
A(A& a) :m_pt(a.m_pt) { m_pt = a.m_pt; }
prevents any instance of A being initialised with a const A.
This also prevents const A a2 = a1 where a1 is const, but you should never need to do this anyway, since you can just use a1 directly - it's const even if you could make a copy, a2 would be forever identical to a1.