In place construction without placement new

D

David

Suppose that I have a class A with a constructor A(B b, C c) and I want
to make a vector of A's. Also, suppose that A's are VERY expensive to
construct, copy, assign. I also want to have a very many vectors of A's
and cannot afford to store a smart pointer to each A as the type in my
vectors.. So I want to write something like:

v.push_back(A(b1,c1));

and not have a sequence which goes like:

.... make space for an A in v at v...
construct A() in v
destruct v
assign A(b1,c1) to v

Unfortunately, this is the behaviour I am seeing in my compiler. I want:

.... make space for an A in v at v...
construct A(b1,c1) in v

Is there any known way to ensure that compilers will give the latter
code? I have a work around, but it is clunky...

Cheers

David
 
A

Alf P. Steinbach

* David:
Suppose that I have a class A with a constructor A(B b, C c) and I want
to make a vector of A's. Also, suppose that A's are VERY expensive to
construct, copy, assign.

Then a raw vector is contraindicated.

I also want to have a very many vectors of A's
and cannot afford to store a smart pointer to each A as the type in my
vectors..
Why?


So I want to write something like:

v.push_back(A(b1,c1));

You don't: no matter what you do you will then have construction of the
argument followed by copying of the argument.

and not have a sequence which goes like:

... make space for an A in v at v...
construct A() in v
destruct v
assign A(b1,c1) to v


That is a quality-of-implementation issue. The implementation should
just copy-construct the argument in the new space. However, given your
earlier remarks even that seems to be one copy-operation too much.

Unfortunately, this is the behaviour I am seeing in my compiler. I want:

... make space for an A in v at v...
construct A(b1,c1) in v

Is there any known way to ensure that compilers will give the latter
code?


No, but you can easily do it yourself.

Off the cuff:


class ConstructorArguments { ... };

class A
{
protected:
A( A const& another ) { ... }
A( ConstructorArguments const& a ) { ... };
A& operator=( A const& other ) { ... }
public:
virtual ~A() { ... }
};


class AVec
{
private:
static ConstructorArguments const* theArgs;

class AWrapper: public A
{
public:
AWrapper(): A( *theArgs ) {}

// Required for std::vector usage.
AWrapper( AWrapper const& another ): A( another ) {}
AWrapper& operator=( AWrapper const& other ) { ... }
};

std::vector<AWrapper> myVector;

public:
AVec( size_t aCapacity ) { myVector.reserve( aCapacity ); }

void pushBackNew( ConstructorArguments const& args )
{
if( myVector.size() == myVector.capacity() )
{
throw std::runtime_error( "Ooops, this would copy" );
}
theArgs = &args;
myVector.resize( myVector.size() + 1 );
}

A& operator[]( size_t i ) { return myVector; }
A const& operator[]( size_t i ) const { return myVector; }
};


assuming 'resize' constructs and does not subsequently assign (check it
out).
 
D

David

* David:

Then a raw vector is contraindicated.



Why?

Very large numbers of them all of which are unique pointers (i.e. apart
from algorithm use, their use count will sit at 1 for the majority of
their existence). So I'd prefer to store them by value, avoiding the
time and space overhead of a smart pointer for each of them and just
passing iterators/references to the items in the vectors.
So I want to write something like:

v.push_back(A(b1,c1));

You don't: no matter what you do you will then have construction of the
argument followed by copying of the argument.

and not have a sequence which goes like:

... make space for an A in v at v...
construct A() in v
destruct v
assign A(b1,c1) to v


That is a quality-of-implementation issue. The implementation should
just copy-construct the argument in the new space. However, given your
earlier remarks even that seems to be one copy-operation too much.


Yes I want to avoid all copying.
Unfortunately, this is the behaviour I am seeing in my compiler. I want:

... make space for an A in v at v...
construct A(b1,c1) in v

Is there any known way to ensure that compilers will give the latter code?


No, but you can easily do it yourself.

Off the cuff:


class ConstructorArguments { ... };

class A
{
protected:
A( A const& another ) { ... }
A( ConstructorArguments const& a ) { ... };
A& operator=( A const& other ) { ... }
public:
virtual ~A() { ... }
};


class AVec
{
private:
static ConstructorArguments const* theArgs;

class AWrapper: public A
{
public:
AWrapper(): A( *theArgs ) {}

// Required for std::vector usage.
AWrapper( AWrapper const& another ): A( another ) {}
AWrapper& operator=( AWrapper const& other ) { ... }
};

std::vector<AWrapper> myVector;

public:
AVec( size_t aCapacity ) { myVector.reserve( aCapacity ); }

void pushBackNew( ConstructorArguments const& args )
{
if( myVector.size() == myVector.capacity() )
{
throw std::runtime_error( "Ooops, this would copy" );
}
theArgs = &args;
myVector.resize( myVector.size() + 1 );
}

A& operator[]( size_t i ) { return myVector; }
A const& operator[]( size_t i ) const { return myVector; }
};


assuming 'resize' constructs and does not subsequently assign (check it
out).


Thanks for the suggestion!

I checked out the implementation and it calls insert (or erase, which
won't happen in my case) which then calls std::fill_n() which uses
operator=. I think that I then am back to quality of implementation? My
'clunky' solution is not all that different from your solution. I think
I may need to sleep on this one!

Cheers

David
 
A

Alf P. Steinbach

* David:
I checked out the implementation and it calls insert (or erase, which
won't happen in my case) which then calls std::fill_n() which uses
operator=.

Well then, give it an AWrapper::eek:perator=. One that doesn't do
anything. For the code to be portable you should do that anyway, now
that I think of it.
 
A

Alf P. Steinbach

* Alf P. Steinbach:
* David:

Well then, give it an AWrapper::eek:perator=. One that doesn't do
anything. For the code to be portable you should do that anyway, now
that I think of it.

Forgot to add: class A then needs a constructor that gives it a dummy
state, invoked by default constructor of AWrapper.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,001
Messages
2,570,254
Members
46,849
Latest member
Fira

Latest Threads

Top