Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constructing "array" of noncopyable objects

I have a class that's inhenerently non-copyable (a thread, so there's no copy semantics that make sense), and I want to have a largeish 'array' of these, identically constructed with a non-default constructor. Note that the array is fixed size.

I can only use the default constructor with C++ arrays, unless I initialise each one independently.

Thread myArray[128];   // uses default constructor - wrong

I can list the object constructors and parameters explicitly, but that's verbose and ugly

Thread myArray[128] = { Thread(params,...), Thread(params,...), ... x 128 ;  // ugly

It seems I can't use stl vectors because the object is non-copyable - event though the vector never changes size. I guess the constructor actually does copying!

std::vector<Thread> myVector(128, Thread(params,...));// won't compile

The way I've though of doing this is with an array of smart pointers and an initialization loop, but maybe I'm missing something:

Is there any other way - maybe with boost containers, or a different container type?

like image 476
Roddy Avatar asked May 18 '11 09:05

Roddy


3 Answers

This may seem like totally crazy (and it probably is), but...

struct ThreadInitValues{
  // your actual params
  int i;
  float f;
};

struct Thread{
    Thread(int i = _init.i, float f = _init.f)
      : _i(i)
      , _f(f)
    {}

    static ThreadInitValues _init;

private:
    // uncopyable
    Thread(Thread const&);
    Thread& operator=(Thread const& other);

    // your actual member
    int _i;
    float _f;
};

ThreadInitValues Thread::_init;

int main(){
    Thread::_init.i = 5;
    Thread::_init.f = 3.14f;
    Thread arr[128];
}

Maybe this works out for you. :) Of course, you now need to watch out if the array is initialized in multithreaded code itself...

like image 175
Xeo Avatar answered Nov 12 '22 16:11

Xeo


A vector of smart pointers, with each instance dynamically allocated, is definitely the simplest way. Otherwise (and I'd only do this if absolutely necessary), you can more or less emulate what std::vector does internally. Something along the lines of:

union
{
    double just_to_ensure_alignment;
    unsigned char data[ sizeof(Thread) * elementCount ];
} array;

//  construct...
for ( int i = 0; i != elementCount; ++ i )
    new (data + i * sizeof(Thread)) Thread(params,...);

//  access...
Thread& getAt( int i )
{
    return reinterpret_cast<Thread*>( data + i * sizeof(Thread) );
}

(I'd actually wrap this in a class, if only to be able to use operator[] instead of getAt.)

like image 3
James Kanze Avatar answered Nov 12 '22 16:11

James Kanze


For new compilers supporting r-value references, being copyable is not necessary for vector elements AFAIK. To use it without copying 128 push_back's should be used (creating new object each time), because creting several objects from a single one is a copying :).

If this way is not available, try boost::ptr_vector or std::vector of boost::shared_ptr.

like image 1
maxim1000 Avatar answered Nov 12 '22 16:11

maxim1000