How does one do a placement new operation on a volatile pointer.
For example, I want to do something like this:
volatile SomeStruct Object;
volatile SomeStruct* thing = &Object;
new (thing) SomeStruct(/*arguments to SomeStruct's constructor*/);
I know this would work if there was no volatile keyword......but how can I do this with a volatile variable?
Note:
Placement new is defined like this:
void* operator new(size_t memoryRequested, void* pointer)
{
return pointer;
}
(By the way here is how GCC implements it):
// Default placement versions of operator new.
inline void* operator new(std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT
{ return __p; }
The problem is that I am trying to convert thing
of type volatile SomeStruct*
to void*
, which is not allowed.
For example if I change the new operator to this:
void* operator new(size_t memoryRequested, volatile void* pointer)
{
return (void*)pointer;
}
It would compile, but would invoke undefined behavior.
C's volatile keyword is a qualifier that is applied to a variable when it is declared. It tells the compiler that the value of the variable may change at any time--without any action being taken by the code the compiler finds nearby.
The volatile qualifier is applied to a variable when we declare it. It is used to tell the compiler, that the value may change at any time. These are some properties of volatile. The volatile keyword cannot remove the memory assignment. It cannot cache the variables in register.
There's no reason for a volatile variable to be stored in any "special" section of memory. It is normally stored together with any other variables, including non-volatile ones. If some compiler decides to store volatile variables in some special section of memory - there's nothing to prevent it from doing so.
Yes, a pointer can be volatile if the variable that it points to can change unexpectedly even though how this might happen is not evident from the code. An example is an object that can be modified by something that is external to the controlling thread and that the compiler should not optimize.
I want to say you can do it like this:
new (const_cast<SomeStruct*>(thing)) volatile SomeStruct(...);
But I'm not actually sure whether this is valid or not. The problem is that since the allocation function returns a void*
into which to construct the volatile SomeStruct
object, accesses to the memory may not have volatile semantics, leading to undefined behavior.
So I'm not sure whether it's legal to use placement new to construct an object into a volatile-qualified block of memory. However, assuming the memory was originally, say, a non-volatile array of char
, this seems like the correct solution.
I know this would work if there was no
volatile
keyword......but how can I do this with avolatile
variable?
Placement new
has to do with constructing an object at a given location. cv-qualifiers are only applied after the object is constructed. The const
-ness or volatile
-ity are only applicable once the object is constructed. In that sense, it makes sense that the placement new
does not provide an overload that accepts a volatile
(or const
) pointer. From the C++ standard (draft) [class.ctor/3] here;
A constructor can be invoked for a
const
,volatile
orconst volatile
object.const
andvolatile
semantics ([dcl.type.cv]) are not applied on an object under construction. They come into effect when the constructor for the most derived object ([intro.object]) ends.
Any attempt to cast away the volatile
leads to undefined behavior, see the cppreference here;
Modifying a
const
object through a non-const
access path and referring to avolatile
object through a non-volatile
glvalue results in undefined behavior.
See also [expr.const.cast/6].
Given the use of the volatile
and the placement new
, the assertion in the question (and some of the comments) is that the object is required for use with a signal handler and maps to a specific location in memory.
There are some alternatives though...
If the specific location is not needed, the best is to not use the placement new
and just add a volatile
qualifer to the object wherever it is declared;
struct SomeStruct {
/*...*/
};
// ...
volatile SomeStruct Object;
If both the placement new
and the volatile
is needed, then reorder their use. Construct the object as required and then add the qualifier;
SomeStruct Object;
// ...
void* p = &Object; // or at the required location
volatile SomeStruct* p2 = new (p) SomeStruct;
Does the struct
have to be volatile? The volatile
parts of the struct
could be internalised/abstracted and the cv-qualifiers of the data would not need to be exposed to the client to begin with, it is dealt with internally to the struct
;
struct SomeStruct {
volatile int data;
void DoSomething()
{
data = 42;
}
};
SomeStruct Object;
/* ... */
void* p = &Object;
auto p2 = new (p) SomeStruct{};
p2->DoSomething();
Internalise the initialise of the volatile object, an alternative is to allow the SomeStruct
to lazy initialise (or re-initialise/reset) itself as needed. Given some of the apparent constraints, this may not be that feasible.
struct SomeStruct {
void Initialise() volatile
{
/*...*/
}
}
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