Consider the following example:
#include <new>
struct FunctionObject
{
int operator()() // non-const, modifies the state of this object
{
i += 1;
j += 2;
return i + j;
}
int i = 0;
int j = 0;
};
struct Wrapper
{
explicit Wrapper(const FunctionObject& input_object)
{
constructed_object = ::new (buffer) FunctionObject(input_object);
}
~Wrapper()
{
constructed_object->~FunctionObject();
}
int operator()() const // const, but invokes the non-const operator() of the internal FunctionObject
{
return (*constructed_object)(); // this call modifies the internal bytes of this Wrapper
}
alignas(FunctionObject) unsigned char buffer[sizeof(FunctionObject)];
FunctionObject* constructed_object = nullptr;
};
int test()
{
const FunctionObject function_object{3, 4};
const Wrapper object_wrapper{function_object}; // this call modifies the internal bytes of a const Wrapper
return object_wrapper();
}
A Wrapper
contains an internal FunctionObject
which is constructed inside the Wrapper
by a placement new.
The Wrapper
object is const
, its operator()
is also const
, but calling it causes the internal state of the object to be modified. In many cases, similar scenarios are undefined behavior in C++.
The question is, is it undefined behavior in this particular case (~ do I need to mark the buffer
as mutable
?), or does the C++ standard allow writing code like this?
This is Undefined Behavior.
From [dcl.type.cv],
Any attempt to modify a const object during its lifetime results in undefined behavior.
Adding the mutable
specifier to buffer
will allow it to be modified by a const
member function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With