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],
Adding the
mutablespecifier tobufferwill allow it to be modified by aconstmember function.