Is temporary object originally const?
Asked Answered
M

2

12

Is this code UB?

struct A
{
 void nonconst() {}
};

const A& a = A{};
const_cast<A&>(a).nonconst();

In other words, is the (temporary) object originally const? I've looked through the standard but cannot find an answer so would appreciate quotations to relevant sections.

Edit: for those saying A{} is not const, then can you do A{}.nonconst() ?

Manoeuvre answered 23/1, 2019 at 20:6 Comment(8)
The temporary itself that is created by A{} is not const. You are simply creating a const reference to it, and then you are casting away that const-ness then accessing the temporary. That does not change the const-ness of the temporary itself. It is not UB to cast away const-ness from a pointer/reference if you are sure the object being pointed/referenced is not actually const. It WOULD be UB if the object were actually const, eg const A a; const A &ref = a; const_cast<A&>(ref).nonconst();Chromonema
You can even bind it to A&&.Fibrinous
I don't think it is really called temporary, as const reference prolongs lifetime in this case.Crackle
In response to your edit, yesOverage
@AlexanderGutenev How do you call it?Counterintelligence
@Fibrinous Temporaries were never inherently immutable in C++; historically you could do string() = "hello" or vector<int>().push_back(1). (And there was no rvalue reference at that time.)Counterintelligence
@RemyLebeau The temporary itself that is created by A{} is not const. In C++17, A{} does not even create a temporary object.Vitascope
@AlexanderGutenev "I don't think it is really called temporary" How do you call it?Counterintelligence
B
9

The initialization of the reference a is given by [dcl.init.ref]/5 (bold mine):

Otherwise, if the initializer expression

  • is an rvalue (but not a bit-field)[...]

then the value of the initializer expression in the first case and the result of the conversion in the second case is called the converted initializer. If the converted initializer is a prvalue, its type T4 is adjusted to type “cv1 T4” ([conv.qual]) and the temporary materialization conversion ([conv.rval]) is applied.

So it means that the type prvalue expression that initialize the reference, A{}, is adjusted to const A.

Then [conv.rval] states:

A prvalue of type T can be converted to an xvalue of type T. This conversion initializes a temporary object ([class.temporary]) of type T.

So the type of the temporary object, bound to the reference is the same as the adjusted prvalue type: const A.

So the code const_cast<A&>(a).nonconst(); is undefined behavior.

Boss answered 23/1, 2019 at 20:19 Comment(2)
So the code const_cast<A&>(a).nonconst(); is undefined behavior I've thought UB is to modify a const object. Here there is no modification.Vitascope
@LanguageLawyer True I supposed the code above was an illustration not the production code. So I did not considered the body of nonconst as meaningfull.Boss
O
3

The type of a temporary is whatever type you declared it with.

Unfortunately, as Oliv points out in their answer reference initialization rules transform the type to match the reference type so in this case a actually refers to a const A. It is basically doing

using const_A = const A;
const A& a = const_A{};

Because you can actually create constant prvalues if you ever want to stop a overload set from accepting a constant prvalue you need to have

ret_type function_name(some_type const&&) = delete;

otherwise if you have

ret_type function_name(some_type const&)

in the overload set it then the constant prvalue would bind to that if you only deleted

ret_type function_name(some_type&&)

instead. You can see this working with

struct bar{};

void foo(bar const&) { std::cout << "void foo(bar const&)\n"; }
void foo(bar&&) =delete;

using c_bar = const bar;

int main()
{   
    foo(c_bar{});
}

Here, void foo(bar const&) gets called since c_bar{} is actually const instead of getting a deleted function error if you had used foo(bar{});. Adding

void foo(bar const&&) = delete;

is needed to actually stop foo(c_bar{}); from compiling.

Overage answered 23/1, 2019 at 20:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.