Roddy
Roddy

Reputation: 68033

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?

Upvotes: 9

Views: 2756

Answers (4)

maxim1000
maxim1000

Reputation: 6365

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.

Upvotes: 1

prabhakaran
prabhakaran

Reputation: 5274

I am not that much big programmer. But did you try this

std::vector<YourObject *> temp_Vec;
for(int i=0;i<128;++i)
    temp_Vec.push_back(new YourObject(arguments));

Upvotes: 0

James Kanze
James Kanze

Reputation: 153929

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.)

Upvotes: 3

Xeo
Xeo

Reputation: 131799

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...

Upvotes: 6

Related Questions