On std::launder, GCC and clang: why such a different behavior? - c++

I was tinkering with the example given on the cppreference launder web page.
The example shown below suggest that either I misunderstood something and introduced UB or that there is a bug somewhere or that clang is to lax or too good.
In doit1(), I believe the optimization done by GCC is incorrect (the function returns 2) and does not take into account the fact that we use the placement new return value.
In doit2(), I believe the code is also legal but with GCC, no code is produced ?
In both situations, clang provides the behavior I expect. On GCC, it will depend on the optimization level. I tried GCC 12.1 but this is not the only GCC version showing this behavior.
#include <new>
struct A {
virtual A* transmogrify(int& i);
};
struct B : A {
A* transmogrify(int& i) override {
i = 2;
return new (this) A;
}
};
A* A::transmogrify(int& i) {
i = 1;
return new (this) B;
}
static_assert(sizeof(B) == sizeof(A), "");
int doit1() {
A i;
int n;
int m;
A* b_ptr = i.transmogrify(n);
// std::launder(&i)->transmogrify(m); // OK, launder is NOT redundant
// std::launder(b_ptr)->transmogrify(m); // OK, launder IS redundant
(b_ptr)->transmogrify(m); // KO, launder IS redundant, we use the return value of placment new
return m + n; // 3 expected, OK == 3, else KO
}
int doit2() {
A i;
int n;
int m;
A* b_ptr = i.transmogrify(n);
// b_ptr->transmogrify(m); // KO, as shown in doit1
static_cast<B*>(b_ptr)->transmogrify(m); // VERY KO see the ASM, but we realy do have a B in the memory pointed by b_ptr
return m + n; // 3 expected, OK == 3, else KO
}
int main() {
return doit1();
// return doit2();
}
Code available at: https://godbolt.org/z/43ebKf1q6

The UB comes from accessing A i; to call the destructor at the end of scope without laundering the pointer. That can let the compiler assume i has not been destroyed by the storage reuse before then.
You need something more like:
alignas(B) std::byte storage[sizeof(B)];
A& i = *new (storage) A;
// ...
static_cast<B*>(std::launder(&i))->~B();
// or: b_ptr->~B();
// or: simply don't call the destructor

Related

A simple question about pointer assignment in c++ function

This is my code, after a = b; in the function, a is still nullptr....
int getBox(int *a) {
int *b = new int;
*b = 3;
a = b;
std::cout << *a;
}
int main() {
int *a = nullptr;
getBox(a);
std::cout << a;
}
I guess it's a very simple problem... Maybe I forgot too much about C++
I'm not sure what you're trying to do, but this row inside the getBox():
a=&b;
Doesn't actually change a in the main, you actually overrides the pointer(the copy that was made by the function), and make it point somewhere else.
You can do something like this(again, I don't see the point) :
int getBox(int ** a){
int *b = new int;
*b=3;
*a=b;
std::cout<<*a;
}
int main(){
int *a= nullptr;
getBox(&a);
std::cout<<a;
}
Let's assume there is some type T. Now here are 3 different kinds of functions:
void f(T a) { // pass by value (this is a copy of the 'a' in main)
a = /* something else */ ;
}
int main() {
T a = /* something */ ;
f(a);
// a is still something
}
void f(T &a) { // pass by reference (this is a reference to the 'a' in main)
a = /* something else */ ;
}
int main() {
T a = /* something */ ;
f(a);
// a is now something else
}
void f(T *a) { // pass by address (this is a pointer to the address the 'a' in main)
*a = /* something else */ ;
}
int main() {
T a = /* something */ ;
f(&a);
// a is now something else
}
Now you can apply this logic to any T you want, such as int, or int*, and the same rules will work. You can try this out with getBox and see the effect of each version, which should help you understand what's going on. Note that you are using the first version (pass by value), but for the result you are expecting, you should use the second version (pass by reference).
If you really want to change what a is pointing to, then you can think it this way maybe it will help to make it a bit easier to understand. A is an int pointer and the function getBox takes a reference that you can modify its value which is an int pointer.
void getBox(int* &a) {
int *b = new int;
*b = 3;
a = b;
std::cout << *a;
}
int main(){
int *a= nullptr;
getBox(a);
std::cout<< *a;
}
This will change the value of a, which is a new pointer value to b.
Yes of course, why should changing a in getBox change the value of a in main? If you think the answer is 'because it's a pointer' then I'm afraid you've misunderstood pointers.
Look at this code
int getBox(int a){
a=3;
std::cout<<a;
}
int main(){
int a= 0;
getBox(a);
std::cout<<a;
}
Setting a=3 in getBox has no effect on a in main. Your code is exactly the same, but for some reason because pointers are involved beginners often think it works differently. It doesn't.
You can however use pointers in this way to change what is being pointed at, that's the important thing, but changing the pointer itself doesn't work in the way you are expecting.
You probably only want to change to getBox(int * & a). You then pass a reference to the pointer a to the function instead of creating a copy of the pointer that points to the same address in your case NULL.

Why does make_shared destroy rvalue-references?

I'm trying to understand how I should use smart pointers efficiently, and I got curious about how they work together with rvalue references. How come std::make_shared (and presumably make_unique as well) uses copy semantics and not move semantics?
Here's a gtest test that showcases what I'm trying to say
#include <memory>
int dtor_calls = 0;
struct MoveSemanticsTest1 {
int data;
~MoveSemanticsTest1() { dtor_calls++; }
};
void reset_move_dtor_calls() {
dtor_calls = 0;
}
TEST(MoveSemanticsSanityTest1, SanityTests) {
reset_move_dtor_calls();
{
MoveSemanticsTest1 a = MoveSemanticsTest1();
}
EXPECT_EQ(1, dtor_calls); // <-- This passes, makes sense
reset_move_dtor_calls();
{
MoveSemanticsTest1 b = {3};
auto a = std::make_shared<MoveSemanticsTest1>(std::move(b));
}
EXPECT_EQ(1, dtor_calls); // <-- This fails, why?
reset_move_dtor_calls();
{
MoveSemanticsTest1 b = {3};
auto a = std::make_shared<MoveSemanticsTest1>(b);
}
EXPECT_EQ(2, dtor_calls); // <-- This passes, makes sense because of the copying
}
The second EXPECT_EQ fails, which hints to the moved b resource doesn't actually move the resource.
reset_move_dtor_calls();
{
MoveSemanticsTest1 b = {3}; //1
auto a = std::make_shared<MoveSemanticsTest1>(std::move(b)); //2
//3
//4
}
In 1) you create a MoveSemanticsTest1.
In 2) you create a MoveSemanticsTest1 by move construction an give it to a shared_ptr. b is in a "moved from" state, but still here.
In 3) you destroy the shared_ptr => it destroy its MoveSemanticsTest1
In 4) you destroy the MoveSemanticsTest1 b.
I count 2 call to the destructor.

deleting reference to dereferenced int

Even though the following piece of code compiles and runs fine i want to know if it is a valid c++ code?
int main()
{
int *i= new int;
cout<<*i;
int &ref=*i;
cout<<ref;
delete &ref; //Especially is this statement valid?
return 0;
}
If it is valid then this must also be valid :
int& getInt() {
int* i = new int;
return *i; // OK?
}
int main(){
int& myInt = getInt(); // these two lines are same as shown in the example above ?
delete &myInt; //is this OK too?
}
It's correct code and it will work on all platforms and compilers.
However, it's probably not best practice as the reference is usually used when the called party retains the ownership of the object.

How do I reserve space on the stack for a non-default constructible?

I would basically write the following piece of code. I understand why it can't compile.
A instance; // A is a non-default-constructable type and therefore can't be allocated like this
if (something)
{
instance = A("foo"); // use a constructor X
}
else
{
instance = A(42); // use *another* constructor Y
}
instance.do_something();
Is there a way to achieve this behaviour without involving heap-allocation?
There are better, cleaner ways to solve the problem than explicitly reserving space on the stack, such as using a conditional expression.
However if the type is not move constructible, or you have more complicated conditions that mean you really do need to reserve space on the stack to construct something later in two different places, you can use the solution below.
The standard library provides the aligned_storage trait, such that aligned_storage<T>::type is a POD type of the right size and alignment for storing a T, so you can use that to reserve the space, then use placement-new to construct an object into that buffer:
std::aligned_storage<A>::type buf;
A* ptr;
if (cond)
{
// ...
ptr = ::new (&buf) A("foo");
}
else
{
// ...
ptr = ::new (&buf) A(42);
}
A& instance = *ptr;
Just remember to destroy it manually too, which you could do with a unique_ptr and custom deleter:
struct destroy_A {
void operator()(A* a) const { a->~A(); }
};
std::unique_ptr<A, destroy_A> cleanup(ptr);
Or using a lambda, although this wastes an extra pointer on the stack ;-)
std::unique_ptr<A, void(*)(A*)> cleanup(ptr, [](A* a){ a->~A();});
Or even just a dedicated local type instead of using unique_ptr
struct Cleanup {
A* a;
~Cleanup() { a->~A(); }
} cleanup = { ptr };
Assuming you want to do this more than once, you can use a helper function:
A do_stuff(bool flg)
{
return flg ? A("foo") : A(42);
}
Then
A instance = do_stuff(something);
Otherwise you can initialize using a conditional operator expression*:
A instance = something ? A("foo") : A(42);
* This is an example of how the conditional operator is not "just like an if-else".
In some simple cases you may be able to get away with this standard C++ syntax:
A instance=something ? A("foo"):A(42);
You did not specify which compiler you're using, but in more complicated situations, this is doable using the gcc compiler-specific extension:
A instance=({
something ? A("foo"):A(42);
});
This is a job for placement new, though there are almost certainly simpler solutions you could employ if you revisit your requirements.
#include <iostream>
struct A
{
A(const std::string& str) : str(str), num(-1) {};
A(const int num) : str(""), num(num) {};
void do_something()
{
std::cout << str << ' ' << num << '\n';
}
const std::string str;
const int num;
};
const bool something = true; // change to false to see alternative behaviour
int main()
{
char storage[sizeof(A)];
A* instance = 0;
if (something)
instance = new (storage) A("foo");
else
instance = new (storage) A(42);
instance->do_something();
instance->~A();
}
(live demo)
This way you can construct the A whenever you like, but the storage is still on the stack.
However, you have to destroy the object yourself (as above), which is nasty.
Disclaimer: My weak placement-new example is naive and not particularly portable. GCC's own Jonathan Wakely posted a much better example of the same idea.
std::experimental::optional<Foo> foo;
if (condition){
foo.emplace(arg1,arg2);
}else{
foo.emplace(zzz);
}
then use *foo for access. boost::optional if you do not have the C++1z TS implementation, or write your own optional.
Internally, it will use something like std aligned storage and a bool to guard "have I been created"; or maybe a union. It may be possible for the compiler to prove the bool is not needed, but I doubt it.
An implementation can be downloaded from github or you can use boost.

C++11 strange behavior with classes, pointers and global scope declarations

[Global Scope]
myClass *objA, *objB, *obj;
int objnum;
I want to switch between objA and objB and assign them alternatively to obj, so in main() I have:
int main()
{
objA = new myClass(parameters...);
objB = new myClass(parameters...);
// start with objA;
objnum = 0;
obj = objA;
}
At some point a function is called that switches between the two objects:
void switchObjects()
{
if (++objnum > 1) objnum = 0;
obj = objnum == 0 ? objA : objB;
}
And in the function where I use the object, I have:
void doYourJob()
{
int res = obj->work();
}
Now the weird thing is that if I don't assign obj to either objA or objB, it still works. I would expect an exception, instead. Even if I do obj = NULL;, it still works! What's this voodoo?
OK, I could provide a different example that brings to the same result, without using a NULL pointer:
myClass *obj[2];
int objnum;
void switchObject()
{
if (++objnum > 1) objnum = 0;
}
void doYourJob()
{
res = obj[objnum]->work();
}
int main()
{
obj[0] = new myClass(parameters...);
obj[1] = new myClass(parameters...);
objnum = 0;
}
With the above code, regardless of the value of objnum, I still get both objects working together, even if I'm calling work() on only one instance.
And if I replace the function doYourJob() with this:
void doYourJob()
{
int res1 = obj[0]->work();
int res2 = obj[1]->work();
}
I always get the results doubled, as if I were calling the function work() twice on every object.
Consider a simpler example:
#include <iostream>
struct X
{
void foo() { std::cout << "Works" << std::endl; }
};
int main() {
X* x = nullptr;
x->foo();
}
With most compilers and on most platforms, this code will appear to work fine, despite having called foo on a null pointer. However, the behaviour is technically undefined. That is, the C++ language gives no restrictions about what might happen if you do this.
Why does it work? Well, calling a member function only requires knowing the type of the object it is being called on. We know that x points at an X, so we know what function to call: X::foo. In many cases, it may be difficult or even impossible to know if a pointer points at a real object, so the compiler just lets it happen. The body of the function, in this case, doesn't actually depend on the X object actually existing, so it just works. This isn't something you can depend on though.