0

I came across this code in Feb 2013 issue of "Overload" Magazine. I understand the code provided, but completly I do miss it's purpose, neither the analogy with std:: auto_ptr and sparing alloc/ dealloc cycles. If someone could re-explain this "recipe" in his own words. The description is as this :

Recipe #2 – Containers with ‘move’ semantics Recipe #2 is admittedly a rather weird one, but every good cookbook should contain at least one weird recipe, so here goes. In high-performance code, there are scenarios, where you need to have a container which stores complex objects (such objects including allocated storage etc.), but those objects are only moved around and are never copied. Providing a copy constructor for such objects can be either difficult (for example, if such an object includes a file handle) or undesirable for performance reasons (if such an object contains allocated memory, copying which would be expensive). One common way to deal with this is to use some kind of reference-counted pointer (or something similar to auto_ptr<>); this is a viable option, but it has the associated cost of extra allocation/ deallocation, and in really high-performance code, this might be an issue. In such cases, an approach similar to the following could help (rephrasing a proverb, you could say that weird times require weird measures) – see Listing 2.

//class X is our complicated class
class StackOfX {
    // stack is just one example; any other type of
    // container (including maps, sets, lists, etc.)
    // can be written in a similar manner
    struct ShadowX { char data[ sizeof(X) ]; };
    typedef vector<ShadowX> ShadowV;
    ShadowV v;
    void push( /* move-in */ X& x ) {
        ShadowX& sx = (ShadowX&)x;
        v.insert( v.end(), sx );
    }
    const X& operator[]( int i ) const {
        return (const X&)v[ i ];
    }
    void pop( /* move-out */ X& x ) {
        ShadowV::iterator it = v.end() - 1;
        ShadowX& sx = (ShadowX&)x;
        sx = *it;
        v.erase( it );
    }
    ~StackOfX() {
        for( ShadowV::iterator it = v.begin();
        it != v.end(); ++it ) {
            X& x = (X&)(*it);
            x.X::~X();
        }
    }

};
sam hocevar
  • 11,853
  • 5
  • 49
  • 68
paul424
  • 153
  • 2
  • 13

2 Answers2

1

The point of the code appears to be able to copy objects that don't support copying, by treating them as sequences of bytes.

It's not a good idea to do that, but if it's to be done it would be more clear to use memcpy than a silly reinterpretation.

C++11 introduced support for move semantics. Before that, for C++03 there was Andrei's Mojo stuff (which however never took off). With move semantics support objects can be put in containers even if they're not copyable.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
0

This is completely obsolete with C++11, which provides syntax for move semantics directly in the language.

Get a book that's actually good and up-to-date, The Definitive C++ Book Guide and List

To quote from that page: there are very many very bad C++ books

Community
  • 1
  • 1
o11c
  • 15,265
  • 4
  • 50
  • 75