17

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.

DarthRubik
  • 3,927
  • 1
  • 18
  • 54
  • @LightnessRacesinOrbit A noble effort.....but it fails – DarthRubik Sep 19 '16 at 23:25
  • 2
    Well... you can't do that. – Kerrek SB Sep 19 '16 at 23:27
  • @KerrekSB But the real question is why........and what is the workaround (if any)? – DarthRubik Sep 19 '16 at 23:30
  • @DarthRubik Sounds more like a XY-problem. So why do you actually need to do that? – πάντα ῥεῖ Sep 19 '16 at 23:31
  • 7
    Perhaps you could explain why you think you need this? – Lightness Races in Orbit Sep 19 '16 at 23:31
  • 1
    Odd, though; 5.3.4/1 reads as if any cv-qualification should be allowed. Once you've `#include`d `` I'd expect `new (p) (volatile SomeStruct)` to work... but it doesn't (as you say). 3.7.4 is like "nope". Oh well; prefer proper memory fences. – Lightness Races in Orbit Sep 19 '16 at 23:32
  • @DarthRubik: Why do you need a work-around? Just don't do this. I'd be really curious to see which large software project design would be blocked because of this problem. – Kerrek SB Sep 19 '16 at 23:38
  • @KerrekSB I am working on an embedded project that has a variable that used in an interrupt and in the main code, so it needs to be volatile, but I also need the placement new operator, because sometimes I have different types in this chunk of memory (like `ClassA`, and `DerivedFromClassA`) – DarthRubik Sep 19 '16 at 23:42
  • @LightnessRacesinOrbit http://coliru.stacked-crooked.com/a/9e17e868625f287e – Brian Bi Sep 19 '16 at 23:43
  • 1
    @Brian: But is the `const_cast` ok or does it take away the entire point? – Lightness Races in Orbit Sep 19 '16 at 23:44
  • @LightnessRacesinOrbit the output seems to indicate that `gcc` is happy with it – DarthRubik Sep 19 '16 at 23:46
  • 2
    @DarthRubik: That it compiles tells us nothing – Lightness Races in Orbit Sep 19 '16 at 23:46
  • @LightnessRacesinOrbit I was only responding to the debate on whether or not you can have `volatile` in the *new-type-id*. Sorry if I didn't make it clear. – Brian Bi Sep 19 '16 at 23:46
  • 5
    @KerrekSB we all know it's going to turn out that it's a variable modified by multiple threads or something and he thinks that `volatile` is relevant – M.M Sep 19 '16 at 23:48
  • @LightnessRacesinOrbit no the output: [see output](http://godbolt.org/#compilers:!((compiler:g6,options:'-O3+-std%3Dc%2B%2B11',source:'%23include+%3Cnew%3E%0Avolatile+char+a%5Bsizeof(int)%5D%3B%0Aint+main()+%7B%0A++++%0A++++volatile+char*+p+%3D+a%3B%0A++++new+(const_cast%3Cchar*%3E(p))+volatile+int%7B0x42%7D%3B%0A%7D')),filterAsm:(binary:!t,colouriseAsm:!t,commentOnly:!t,directives:!t,intel:!t,labels:!t),version:3) – DarthRubik Sep 19 '16 at 23:50
  • @M.M That is not what I am doing.......I am on an `avr` micro controller, and `volatile`ing variables in interrupts is standard practice [see link](http://www.avrfreaks.net/forum/tutcoptimization-and-importance-volatile-gcc) – DarthRubik Sep 19 '16 at 23:51
  • 1
    @DarthRubik: Yes, I can see the output. That tells us nothing about whether this construct assuredly behaves the way you want it to, in a non-contrived example. Is this well-defined? Is the volatility enforced at all stages of the data pipeline? – Lightness Races in Orbit Sep 19 '16 at 23:52
  • Changing types seems a little over-stretching the meaning of volatile. How would you ensure that the interrupt didn't come along and write TypeA into the chunk while you were in the middle of `new (*ptr) TypeB`? – kfsone Sep 20 '16 at 00:02
  • 2
    @DarthRubik that's exactly what you are doing and it is bad technique when used on anything bigger than 1 byte – M.M Sep 20 '16 at 00:02
  • @kfsone Whenever I access this structure, I disable interrupts, and then re-enable them after wards, so that multi byte structures are not subject to what you are describing – DarthRubik Sep 20 '16 at 00:04
  • 2
    If interrupts are disabled then you do not need `volatile` because there is no possibility of an interrupt ... You're doing it wrong. The guy you linked to gets away with it because he is only using volatile on `char` and not a more complicated object – M.M Sep 20 '16 at 00:07
  • 2
    For more info see [Nine ways to break your systems code using volatile](http://blog.regehr.org/archives/28) – M.M Sep 20 '16 at 00:11
  • @M.M Look....This is not really the the place to argue about this.....if you want we can setup a chat room to talk about this, but this is not the place – DarthRubik Sep 20 '16 at 00:13
  • `thing` gets its memory from somewhere. As a workaround, could you store that pointer into another non-volatile variable and use that in the `new` call? (`SomeStruct *tblob = ...; thing = tblob; new tblob(SomeStruct(...));`) – 1201ProgramAlarm Sep 23 '16 at 01:54
  • 1
    The code as shown would **not** work sans the `volatile` keyword. It has **Undefined Behavior**, using an indeterminate (uninitialized) pointer. Once you include where or how you get that pointer, the answer is probably trivial: just belay adding `volatile` until after the construction of an object there. – Cheers and hth. - Alf Sep 23 '16 at 21:33
  • So.... let me understand this correctly... you're doing **port I/O** using **placement new**, that's why you need this so badly? – rustyx Sep 26 '16 at 19:13

3 Answers3

8

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.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
  • 2
    The standard probably doesn't cover this at all, `volatile` qualifiers qualify objects but the object doesn't exist until the constructor has finished. – M.M Sep 19 '16 at 23:41
  • 1
    @M.M If you have an array of volatile char, then you do have volatile char objects even if they are not initialized yet (in that case they simply have indeterminate value). But placement new is interesting, it seems to be exempt from some of the rules that apply in other circumstances. So really I don't know for sure. – Brian Bi Sep 19 '16 at 23:42
  • I suppose you could say that when you do placement new, you implicitly end the lifetime of any objects that were already there (although without calling the destructor, if there is one) so the buffer is not volatile anymore. – Brian Bi Sep 19 '16 at 23:45
  • @Brian: Arguably the buffer itself is an object and it's volatile and its lifetime has not ended yet (though this depends on the example) – Lightness Races in Orbit Sep 19 '16 at 23:45
  • @Brian in reality though, you want to mark space as volatile because it may be altered by an external factor -- whether or not it has objects in it – M.M Sep 19 '16 at 23:47
  • @M.M: On the other hand, if the space itself is an external factor then you have no means by which to do so; the only `volatile` thing you have is the pointee in the pointer type. This whole thing is blerghergherghegr to me. – Lightness Races in Orbit Sep 19 '16 at 23:48
  • @LightnessRacesinOrbit The standard says you can end the lifetime of an object by reusing the storage it occupies. If the entire char array is volatile, we can still say that its lifetime ends when we reuse the storage via placement new, I think? – Brian Bi Sep 19 '16 at 23:54
  • @Brian: No, I don't think so. You end the lifetime of the objects previously occupying that space, but if you were to end the lifetime of the space itself (the `char` array) then your reuse of it for new objects wouldn't be well defined! But I've always found placement new rules to be partially ambiguous at best, so meh :( – Lightness Races in Orbit Sep 19 '16 at 23:54
  • @LightnessRacesinOrbit No, you wouldn't be ending the lifetime of the space, you would be ending the lifetime of the char array (considered as a complete object) occupying that space, and then the space would no longer have a type since there is no object there anymore. But yes I agree with you, this is one of the more poorly specified areas of the standard, and I can't be sure whether I'm right. – Brian Bi Sep 19 '16 at 23:56
  • Even if this is valid there's still the issue that constructors cannot be `volatile`, so the object constructor is going to cause UB by writing volatile space via non-volatile lvalues – M.M Sep 20 '16 at 00:16
  • @M.M Only if you don't believe that the memory becomes non-volatile the instant before construction begins – Brian Bi Sep 20 '16 at 00:28
  • @Brian It seems that this solution works, because the compiler cannot optimize away a constructor call, unless it is a copy constructor...... – DarthRubik Sep 28 '16 at 12:03
7

I know this would work if there was no volatile keyword......but how can I do this with a volatile 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 or const volatile object. const and volatile 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 a volatile 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
    {
        /*...*/
    }
}
Niall
  • 30,036
  • 10
  • 99
  • 142
0

I think this may help you with what it is you are trying to achieve. Now the template class I'm showing you is written with use of the Windows Platform for locking threads, you can modify this class to work with other OS - Platforms as needed. It is just used as an illustration of how one could achieve the above semantics. This does compile, run and exits with a code of 0 for Visual Studio 2015 CE. This class does rely on the <Windows.h> header file for the use of CRITICAL_SECTION, EnterCriticalSection(), LeaveCriticalSection(), InitializeCriticalSection() & DeleteCriticalSection(). If there is an alternative to these with in other libraries such as the boost library this class can easily be written to achieve the same functionality. This class is designed to lock a user defined class object as volatile while working across multiple threads.

VolatileLocker.h

#ifndef VOLATILE_LOCKER_H
#define VOLATILE_LOCKER_H

#include <Windows.h>

template<typename T>
class VolatileLocker {
private:
    T*  m_pObject;
    CRITICAL_SECTION* m_pCriticalSection;

public:
    VolatileLocker( volatile T& objectToLock, CRITICAL_SECTION& criticalSection );
    ~VolatileLocker();

    T* operator->();

private:
    VolatileLocker( const VolatileLocker& c ); // Not Implemented
    VolatileLocker& operator=( const VolatileLocker& c ); // Not Implemented

}; // VolatileLocker

#include "VolatileLocker.inl"

#endif // VOLATILE_LOCKER_H

VolatileLocker.inl

// ----------------------------------------------------------------------------
// VolatileLocker()
// Locks A Volatile Variable So That It Can Be Used Across Multiple Threads Safely
template<typename T>
VolatileLocker<T>::VolatileLocker( volatile T& objectToLock, CRITICAL_SECTION& criticalSection ) :
    m_pObject( const_cast<T*>( &objectToLock ) ),
    m_pCriticalSection( &criticalSection ) {
    EnterCriticalSection( m_pCriticalSection );
} // VolatileLocker

// ----------------------------------------------------------------------------
// ~VolatileLocker()
template<typename T>
VolatileLocker<T>::~VolatileLocker() {
    LeaveCriticalSection( m_pCriticalSection );
} // ~VolatileLocker

// ----------------------------------------------------------------------------
// operator->()
// Allow The Locked Object To Be Used Like A Pointer
template <typename T>
T* VolatileLocker<T>::operator->() {
    return m_pObject;
} // operator->

VolatileLocker.cpp

#include "VolatileLocker.h"

Now here is the main running application that uses the templated volatile locker class and the use of the placement new operator.

#include <iostream>
#include "VolatileLocker.h"

static CRITICAL_SECTION s_criticalSection;

class SomeClass {
private:
    int m_value;

public:
    explicit SomeClass( int value ) : m_value( value ) {}

    int getValue() const { return m_value; }

}; // SomeClass

int main() {
    InitializeCriticalSection( &s_criticalSection ); // Initialize Our Static Critical Section

    SomeClass localStackObject( 2 ); // Create A Local Variable On The Stack And Initialize It To Some Value

    // Create A Pointer To That Class And Initialize It To Null.
    SomeClass* pSomeClass = nullptr;
    // Not Using Heap Here, Only Use Local Stack For Demonstration, So Just Get A Reference To The Stack Object
    pSomeClass = &localStackObject;

    // Here Is Our Pointer / Reference To Our Class As A Volatile Object 
    // Which Is Also Locked For Thread Safety Across Multiple Threads
    // And We Can Access The Objects Fields (public variables, methods) via
    // the VolatileLocker's overloaded ->() operator.
    std::cout << VolatileLocker<SomeClass>( *pSomeClass, s_criticalSection )->getValue() << std::endl;

    // Placement New Operator On Our Pointer To Our Object Using The Class's Constructor
    new (pSomeClass) SomeClass( 4 );

    // Again Using The Volatile Locker And Getting The New Value.
    std::cout << VolatileLocker<SomeClass>( *pSomeClass, s_criticalSection )->getValue() << std::endl;

    // Here Is The Interesting Part - Let's Check The Original Local Stack Object
    std::cout << localStackObject.getValue() << std::endl;

    // Cleaning Up Our Critical Section.
    DeleteCriticalSection( &s_criticalSection );
    return 0;
} // main

Output

2
4
4

NOTE:

Something to be aware of. The initial local stack variable itself is not volatile. If you try to declare the stack variable as volatile and used it directly as such:

volatile SomeClass localStackObject( 2 );
SomeClass* pSomeClass = nullptr;
pSomeClass = &localStackObject; // Invalid - volatile SomeClass* cannot be assigned to an entity of type SomeClass*

If you try to work around this by using the volatile local variable directly you can still use it with the VolatileLocker, but you won't be able to use the Placement New as this snippet shows:

std::cout << VolatileLocker<SomeClass>( localStackObject, s_criticalSection )->getValue() << std::endl; // Line Okay - Notice using object directly and no dereferencing.

// However when we get to this line of code here:
new (localStackObject) SomeClass( 4 ); // Does Not Compile. There Is No Instance Of Operator New To Match The Argument List

// To Fix That We Can Do This:
new ( const_cast<SomeClass*>( &localStackObject) ) SomeClass( 4 ); // This Will Compile

However to access any members using this design method you would then have to use the VolatileLocker to access the class's methods so the localStackObject can not be used directly .

// This Is Invalid:
std::cout << localStackObject.getValue() << std::endl; 

// Use This Instead:   
std::cout << VolatileLocker<SomeClass>( localStackObject, s_criticalSection )->getValue() << std::endl;

As an important reminder note this class was originally designed with the specific windows platform in mind, however, the concept of this template class can easily be written with cross-platform modularity in mind just by replacing the CRITICAL_SECTION with any available cross-platform equivalent functions.

Here is a reference answer for working with Linux / Unix based systems: stackoverflow/multithreading/linux

Here is a reference answer for working with Mac / Apple based systems: stackoverflow/multithreading/mac

Here are references to write cross-platform modularity equivalents:

  1. cppreference/thread
  2. cppreference/condition_variable
Community
  • 1
  • 1
Francis Cugler
  • 7,788
  • 2
  • 28
  • 59
  • There is a difference between being thread safe and being a volatile variable........I don't believe that this will work for me because I am on an embedded device.......it has no concepts of threads and such.......but I do need a volatile variable, because of interrupts. – DarthRubik Sep 22 '16 at 20:54
  • Oh okay; but still the template class keeps a pointer to the object class passed into its constructor which takes a reference or address of volatile type. The design of the class was for the purpose of being thread safe as it was used in an OpenGL application. I'm sure there are ways to modify this class to suite your needs. If I have more time I could look into the OpenGL API that is geared toward embedded devices to see what I could find. I'm not 100% certain, but there could be a way to do this using an asm block of code within your c++ source. (...more) – Francis Cugler Sep 23 '16 at 02:32
  • (...continued) In my source code where I use this class within my OpenGL Shader Engine, my Game class contains a volatile variable of a GameState object type. Since the game switches between multiple states such as Menu, Loading, Game Play, Credits etc., and the fact that I have OpenGL and other objects setup to work with multithreading, I use this class to get or change the GameState that belongs to the Game Class object where that gameState is a volatile so I end up passing in the pointer to my Game class to retrieve the game state object, however I do not use the Placement New in my code. – Francis Cugler Sep 23 '16 at 02:38
  • I am intrigued by your question, it got me into thinking on how to achieve this. – Francis Cugler Sep 23 '16 at 02:39