Michael Ivanov Michael Ivanov -4 years ago 162
C++ Question

Disable implicit object copy selecively

I have the following API design problem,or rather dilemma.I seek a way to store some objects in STL vector as object.Yes,I look for a way to increase vector traversing performance through cache locality improvement. Now, the thing is, that type of object should also be exposed as non-copiable to the user of the API. And I mean implicit copy via copy constructor or assignment.
But as you surely know, doing something like this:

#define PREVENT_COPY(TypeName) \
TypeName (const TypeName &); \
void operator= (const TypeName &);
#endif

class FooClass
{
PREVENT_COPY(FooClass)
public:
FooClass() {}
~FooClass() {}
};


And then:

int main(int argc,char* argv[])
{
std::vector<FooClass> fooVec;
}


Won't work, because the vector requires access to copy constructor.So ideally,I would want to enjoy both worlds,that's being able to prevent public access to copy/assignment mechanism while still being able to push objects into vector.
C array can replace STL vector.But is there a hack to get it working also with std::vector in such a scenario?

As a side note:
The reason why I need to disable implicit copy for that type of object is that it's created and managed by an internal system,which is responsible for the whole life cycle of objects of that type.And currently I cache those in a vector of pointers.The target are mobile platforms and the app is real time rendering system.I want to minimize dynamic allocations and improve cache locality for frequently traversed vectors of performance critical data.

Answer Source

This is exactly what rvalue references (introduced in C++11) are for. If you wish to have a single non-copyable instance that you transfer from one place to the other, you can use move-semantics along with std::vector::emplace_back.

For example:

#include <iostream>
#include <vector>

struct Foo
{
    Foo( int b ) : bar(b) {}

    Foo( const Foo& ) = delete;
    Foo& operator=( const Foo& ) = delete;

    ~Foo() = default;
    Foo( Foo&& f ) = default;
    Foo & operator=( Foo && ) = default;

    int bar;
};


int main()
{
    std::vector<Foo> foos;
    foos.emplace_back( Foo(4) );
    Foo f(2);
    foos.emplace_back( std::move( f ) );
    // Now the contents of 'f' must be considered invalid, and
    // using 'f' is undefined behavior.

    for( const Foo & f : foos )
    {
        std::cout << f.bar << std::endl;
    }
    return 0;
}

Output:

4
2

This is a naive example because it's using trivial data types and defaulted move-construction. But hopefully you get the picture.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download