By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,421 Members | 1,128 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,421 IT Pros & Developers. It's quick & easy.

Classes with reference members in a vector.

P: n/a
Hi all,

I am trying to make a vector containing objects the have a reference
member. However, as soon as I try to push_back an element into this
vector, g++ balks at the fact that it needs to instantiate an operator=
on the class containing the reference members (see below for what I try
to do).

#include <vector>

class TestClass {
private:
const int & m_q;
public:
TestClass(const int & q) { m_q = q; }
};

int main()
{
std::vector<TestClass> v;
int hello = 5;
v.push_back(TestClass(hello));
}

I would have expected that a copy constructor call would be executed in
the offended line instead of an assignment.

Can anyone explain how the desired operation could be implemented (or
why it doesn't make sense for me to want it to work?).

Best regards, Sidney

Jun 28 '06 #1
Share this Question
Share on Google+
23 Replies


P: n/a
Oops. In the previous mail, please read ...

TestClass(const int & q): m_q(q) { }

.... for the constructor definition. It should be immediately
initialized, of course.... But the problem remains.

Cheerio,

Sidney

Jun 28 '06 #2

P: n/a

si****@jigsaw.nl wrote:
Oops. In the previous mail, please read ...

TestClass(const int & q): m_q(q) { }

... for the constructor definition. It should be immediately
initialized, of course.... But the problem remains.

Cheerio,

Sidney


I dont think you can have references inside a STL container (like
Vector). Mainly because of issues while copying. A reference, unlike a
pointer, can only be set once.

HTH,
Vikram

Jun 28 '06 #3

P: n/a

Vikram wrote:
I dont think you can have references inside a STL container (like
Vector). Mainly because of issues while copying. A reference, unlike a
pointer, can only be set once.


That could well be an STL design decision or limitation that I am not
aware of. Note, however, that at no point I want to set a reference
more than once.

Jun 28 '06 #4

P: n/a

si****@jigsaw.nl wrote:
Vikram wrote:
I dont think you can have references inside a STL container (like
Vector). Mainly because of issues while copying. A reference, unlike a
pointer, can only be set once.

This is not true. A reference can be set many times unless it is const.
You must however assign a value to it when it is constructed.

That could well be an STL design decision or limitation that I am not
aware of. Note, however, that at no point I want to set a reference
more than once.


In order to grow the vector often a new one is needed. The code then
allocates the new vector and copies the old members into it - this will
use an assignment.

Depending on the implementation and how you use it in the rest of your
code you may be able to get away with a std::list. To get some proper
advice though we'd need to know a lot more about what you want to
achieve.
K

Jun 28 '06 #5

P: n/a

Kirit Sælensminde wrote:
si****@jigsaw.nl wrote:
Vikram wrote:
I dont think you can have references inside a STL container (like
Vector). Mainly because of issues while copying. A reference, unlike a
pointer, can only be set once.


This is not true. A reference can be set many times unless it is const.
You must however assign a value to it when it is constructed.

Sorry..but how? I am not aware of any way to re-assign a reference
variable. Infact, Scott Meyer's "More effective C++" has that as the
1st item.
Maybe I am missing something here

--Vikram

Jun 28 '06 #6

P: n/a
Vikram posted:

Kirit Sælensminde wrote:
si****@jigsaw.nl wrote:
> Vikram wrote:
>
> > I dont think you can have references inside a STL container (like
> > Vector). Mainly because of issues while copying. A reference,
> > unlike a pointer, can only be set once.


This is not true. A reference can be set many times unless it is
const. You must however assign a value to it when it is constructed.

Sorry..but how? I am not aware of any way to re-assign a reference
variable. Infact, Scott Meyer's "More effective C++" has that as the
1st item.
Maybe I am missing something here


I presume, (although I don't know if he meant it in a smart-alaky way),
that he mean that you can do:

int i;

int &r = i;

int a = 1, b = 2, c = 3, d = 4;

r = a; r = b; r = c; r = d;
However, any C++ programmer who's out of diapers will tell you that
you're setting the value of "i", NOT changing the object to which the
reference refers.

If you ever change the object to which a reference refers, I'll give you
my house, and also eat my hat for good measure.
--

Frederick Gotham
Jun 28 '06 #7

P: n/a

Kirit Sælensminde wrote:
In order to grow the vector often a new one is needed. The code then
allocates the new vector and copies the old members into it - this will
use an assignment.
Why does it allocate (calling a constructor), then assign? To me it is
not inconceivable that one could gop around this, by having the
push_back() using the copy constructor for combined allacation and
assignment.
Depending on the implementation and how you use it in the rest of your
code you may be able to get away with a std::list.
I need random access via operator[], so a vector is needed.
To get some proper advice though we'd need to know a lot more about what you want to
achieve.


I have a Class that contains references to items that are managed by a
different class, i.e., the Class isn't responsible for their
deallocation, and it may assume that the referenced items exist during
its lifetime, furthermore, I don't need the ability to set them to NULL
- in fact, I would like the help of the compiler to make sure that
doesn't happen.

Currently I just use pointer members but IMHO it would be preferable to
turn the members into references because of these guarantees - the
referred members /are/ properly thought of as aliases of the objects
themselves, instead of pointers to them, making references the natural
choice.

So basically all would be swell if I could just put an instance of
these classes in a vector, which is a-priori not much to ask. It could
be a genuine limitation of the STL but I would be interested if there
were a deeper reason that what I want would be bad.

I don't see an a-priori reason why one /can/ have a class C with
reference members, but one /cannot/ have a usable std::vector<C>. This
issue is independent of my particular problem in my particular program,
it is more a generic question about understanding why this seems to be
a problem with STL or C++.

Jun 28 '06 #8

P: n/a
Take a look at the code for push_back (g++ 3.3) in
/usr/local/c++/3.3/bits/stl_vector.h.

If there is space to spare then the copy constructor is used to
append your new object (using _Construct, which amounts to a
placement new operation). However, if there isn't enough space
available
and the vector needs to reallocate storage, then _M_insert_aux is
called. This is the cause of the problem, and is more obscure (code in
vector.tcc)
because _m_insert_aux is also designed for inserting anywhere in the
vector,
not just at the end. For push_back, the code executed only needs to
use the
copy constructor (for both the copy of the existing objects and the
append of
your new object). Unfortunately, the alternate branch in the 'if' uses
the
assignment operator, and that is why the compiler complains...

In my opinion, the use of _M-insert_aux in push_back was a poor choice.
There
is no need for the runtime-evaluation of 'if', and it could be
implemented so
that operator= does not need to be instanciated by the compiler.
Perhaps other STL implementations are different and this is just a g++
issue.

Ian

Jun 28 '06 #9

P: n/a

Frederick Gotham wrote:
Vikram posted:
Kirit Sælensminde wrote:
si****@jigsaw.nl wrote:
> Vikram wrote:
>
> > I dont think you can have references inside a STL container (like
> > Vector). Mainly because of issues while copying. A reference,
> > unlike a pointer, can only be set once.

This is not true. A reference can be set many times unless it is
const. You must however assign a value to it when it is constructed.

Sorry..but how? I am not aware of any way to re-assign a reference
variable. Infact, Scott Meyer's "More effective C++" has that as the
1st item.
Maybe I am missing something here


I presume, (although I don't know if he meant it in a smart-alaky way),
that he mean that you can do:

int i;

int &r = i;

int a = 1, b = 2, c = 3, d = 4;

r = a; r = b; r = c; r = d;
However, any C++ programmer who's out of diapers will tell you that
you're setting the value of "i", NOT changing the object to which the
reference refers.

If you ever change the object to which a reference refers, I'll give you
my house, and also eat my hat for good measure.


Your house and hat are obviously safe :-) I just explained it very
badly in my haste to answer the second half.
K

Jun 28 '06 #10

P: n/a
Kirit Sælensminde posted:

If you ever change the object to which a reference refers, I'll give you
my house, and also eat my hat for good measure.


Your house and hat are obviously safe :-) I just explained it very
badly in my haste to answer the second half.

I also would have accepted:

Use std::swap!
: )
--

Frederick Gotham
Jun 28 '06 #11

P: n/a
Perhaps other STL implementations are different and this is just a g++
issue.


Thanks Ian. If I hear what you're saying, there is no reason (technical
or philosophical) why the code originally provided shouldn't work.

The question then becomes whether the g++ behavior violates the STL
standard in any way....

Does the STL spec make any statements regarding which types of
operations may instantiate which types of operators, constructors, copy
constructors, and such?

If not, it is extremely hairy to write code that is 100% portable
across STL implementations. The programmer would have no way of knowing
if his code will port to a different implementation without trying -
there will be no guarantees.

If yes, I can go look it up and see if I violate any rules...

If not, I can file a bug report with the g++ people.

If yes I will just sob a bit :-/

Does anyone know?

Jun 28 '06 #12

P: n/a
sid...@jigsaw.nl wrote:
Does anyone know?


Ahh ... ISO/IEC 14882, Clause 23.4 (which talks about the requirements
for objects to be stored in STL containers...)

#3 The type of objects stored in these components must meet the
requirements of 'CopyConstructible' types (20.1.3) and the additional
requirements of 'Assignable' types.

..... and the 'Assignable' types requirement, basically, requires a
working operator=().

So it looks like I'm screwed. Anything that you drop in any STL
container must be assignable. Which basically means that you cannot
portably put ANY classes with reference-type members inside /any/ STL
container.

That's rather a hefty restriction, I would say!

Cheerio,

Sidney

Jun 28 '06 #13

P: n/a

si****@jigsaw.nl wrote:
sid...@jigsaw.nl wrote:
Does anyone know?


Ahh ... ISO/IEC 14882, Clause 23.4 (which talks about the requirements
for objects to be stored in STL containers...)

#3 The type of objects stored in these components must meet the
requirements of 'CopyConstructible' types (20.1.3) and the additional
requirements of 'Assignable' types.

.... and the 'Assignable' types requirement, basically, requires a
working operator=().

So it looks like I'm screwed. Anything that you drop in any STL
container must be assignable. Which basically means that you cannot
portably put ANY classes with reference-type members inside /any/ STL
container.

That's rather a hefty restriction, I would say!

Cheerio,

Sidney


Well, it is based on an "Assignable Model" so I guess that is expected.
I think thats the least restriction that can be put especially if
algorithms like copy/sort are to be supported. Not to mention the
internal copying that goes on as someone else pointed out.

Jun 28 '06 #14

P: n/a

Vikram wrote:
Well, it is based on an "Assignable Model" so I guess that is expected.
I think thats the least restriction that can be put especially if
algorithms like copy/sort are to be supported. Not to mention the
internal copying that goes on as someone else pointed out.


I am not an STL expert by any stretch of the imagination, but I am
having a hard time seeing why Assignable is definitely needed on top of
CopyConstructible, - i.e., why the standard writers elected to do this.

I imagine that both copy() and sort() can be written in terms of
copy-constructors rather than operator=.

Anyway, I will have to deal with it. No reference members in classes
that go into STL containers.... It just makes some classes rather less
clean than they could be, for no apparent reason (to me at least). At
least when I would like to put them in STL containers.

Having to declare class members as pointers rather than references
because the STL containers are unable to handle them properly makes me
a bit uncomfortable I must say.

Jun 28 '06 #15

P: n/a
si****@jigsaw.nl wrote:
I am not an STL expert by any stretch of the imagination, but I am
having a hard time seeing why Assignable is definitely needed on top of
CopyConstructible, - i.e., why the standard writers elected to do this.
I imagine that both copy() and sort() can be written in terms of
copy-constructors rather than operator=.


You can write your own container without that restriction. The standard
containers aims to be for general use, but not to solve all possible
problems in any conceivable circumstance.

--
Salu2

Inviato da X-Privat.Org - Registrazione gratuita http://www.x-privat.org/join.php
Jun 28 '06 #16

P: n/a

<si****@jigsaw.nl> wrote in message
news:11*********************@j72g2000cwa.googlegro ups.com...

Vikram wrote:
Well, it is based on an "Assignable Model" so I guess that is expected.
I think thats the least restriction that can be put especially if
algorithms like copy/sort are to be supported. Not to mention the
internal copying that goes on as someone else pointed out.
I am not an STL expert by any stretch of the imagination, but I am
having a hard time seeing why Assignable is definitely needed on top of
CopyConstructible, - i.e., why the standard writers elected to do this.

I imagine that both copy() and sort() can be written in terms of
copy-constructors rather than operator=.


You _could_ write a sort so that every time you swapped items, you created
new ones using their copy constructors and then deleted the old ones. But
that would be pretty inefficient, wouldn't it? Especially if
construction/destruction were expensive for the given class. Assignment is
the usual way.
Anyway, I will have to deal with it. No reference members in classes
that go into STL containers.... It just makes some classes rather less
clean than they could be, for no apparent reason (to me at least). At
least when I would like to put them in STL containers.


You could always store pointers to your objects in the vector, instead of
the objects themselves. (It seems as if that's what I always end up doing
anyway, for one reason or another.)

-Howard


Jun 28 '06 #17

P: n/a

Julián Albo wrote:
You can write your own container without that restriction. The standard
containers aims to be for general use, but not to solve all possible
problems in any conceivable circumstance.


I don't think that what I want to do is particularly exotic, to be
honest. C++ has references which is nice. It has the STL, which is
nice. It's just a pity to conclude that they don't get along too well.

Jun 28 '06 #18

P: n/a

si****@jigsaw.nl wrote:
Vikram wrote:
I imagine that both copy() and sort() can be written in terms of
copy-constructors rather than operator=.
- Especially sorting requires swapping. This requires assignment.
- Copying, especially when having two established ranges, require
assignment, else explicitly calling destructor and inplace construction
would be required - what if inplace construction through exception?
Then the container would be left in an unusable state. Impossible to
write exception safe (value semantics) container if assignment not
allowed (my guess).

Anyway, I will have to deal with it. No reference members in classes
that go into STL containers.... It just makes some classes rather less
clean than they could be, for no apparent reason (to me at least). At
least when I would like to put them in STL containers.
You have many options - why not use pointers, or boost::shared_ptr - it
is copyable and assignable and can be used in containers.
Having to declare class members as pointers rather than references
because the STL containers are unable to handle them properly makes me
a bit uncomfortable I must say.


I would not use reference members in the first place. They give you a
false sense of security. If you want to share objects, use something
like boost::shared_ptr.

One last thing, if you really want to use references in your containers
(no reason to, apart from proving you can) - have a look at boost::ref
library. This is probably not its (initial) intent though.

Code would look something like this. I only checked that it compiled -
requires the boost library of course, but you could easily write your
own ref wrapper...

#include <boost/ref.hpp>
#include <vector>
#include <iostream>

int main()
{
typedef boost::reference_wrapper<int> irefWrapper;
typedef std::vector<irefWrapper> ref_vect;

int v1( 0 );
int v2( 1 );
int& r1( v1 );
int& r2( v2 );

ref_vect rvect;
rvect.push_back( irefWrapper( r1 ) );
rvect.push_back( irefWrapper( r2 ) );

std::copy( rvect.begin(), rvect.end(),
std::ostream_iterator<int>(std::cout, " Missipi \n") );
std::cin.get();
return 0;
}

Regards,

Werner

Jun 28 '06 #19

P: n/a

Howard wrote:
You _could_ write a sort so that every time you swapped items, you created
new ones using their copy constructors and then deleted the old ones.
A swap would be much preferable, you are right. Which makes another
interesting case - it will be impossible to swap two instances of
classes that have reference-type members.
that would be pretty inefficient, wouldn't it? Especially if
construction/destruction were expensive for the given class. Assignment is
the usual way.
I have a hard time thinking of scenarios where the combined default
constructor and operator= would outperform a well-written copy
constructor?
You could always store pointers to your objects in the vector, instead of
the objects themselves. (It seems as if that's what I always end up doing
anyway, for one reason or another.)


Still, a vector of /references/ would often come in handy I suppose.
And, in my particular app I'm trying to store pairs of references -
which would have been quite cheap. It's now just a vector of pointer
pairs.

Regards,

Sidney

Jun 28 '06 #20

P: n/a
si****@jigsaw.nl wrote:
You can write your own container without that restriction. The standard
containers aims to be for general use, but not to solve all possible
problems in any conceivable circumstance.

I don't think that what I want to do is particularly exotic, to be
honest. C++ has references which is nice. It has the STL, which is
nice. It's just a pity to conclude that they don't get along too well.


When you need something similar to a reference but want to be able to make
it refers to some other thing, you can use a pointer. If you want to store
objects in a standard container, the objects must follow the requisites. If
you don't want to meet the requisites or don't want to use pointers you can
use another type or container. Nothing exotic, just using the more
convenient tool for the job.

--
Salu2

Inviato da X-Privat.Org - Registrazione gratuita http://www.x-privat.org/join.php
Jun 28 '06 #21

P: n/a

werasm wrote:
would be required - what if inplace construction through exception?


line above should read:
would be required - what if inplace construction throws an exception?
Regards,

Werner

Jun 28 '06 #22

P: n/a
In article <11**********************@75g2000cwc.googlegroups. com>,
si****@jigsaw.nl says...

[ ... ]
I would have expected that a copy constructor call would be executed in
the offended line instead of an assignment.


The standard containers require that any object stored in them be
copyable and assignable. Regardless of the why it's that way, if your
class isn't copyable and assignable, then you can't store it in a
standard container. I suppose it might work sometimes with some
implementations under some circumstances, but if so, it's purely
accidental.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jun 30 '06 #23

P: n/a

<si****@jigsaw.nl> wrote in message
news:11*********************@i40g2000cwc.googlegro ups.com...

Howard wrote:
You _could_ write a sort so that every time you swapped items, you
created
new ones using their copy constructors and then deleted the old ones.


A swap would be much preferable, you are right. Which makes another
interesting case - it will be impossible to swap two instances of
classes that have reference-type members.


That was my whole point.
that would be pretty inefficient, wouldn't it? Especially if
construction/destruction were expensive for the given class. Assignment
is
the usual way.


I have a hard time thinking of scenarios where the combined default
constructor and operator= would outperform a well-written copy
constructor?


Who said anything about default construction? I was comparing
construction+destruction against assignment. Why would you have to create a
new object in order to call operator=()?
You could always store pointers to your objects in the vector, instead of
the objects themselves. (It seems as if that's what I always end up
doing
anyway, for one reason or another.)


Still, a vector of /references/ would often come in handy I suppose.
And, in my particular app I'm trying to store pairs of references -
which would have been quite cheap. It's now just a vector of pointer
pairs.


I'm not sure how references are any "cheaper" than pointers.

But if you really want your objects to hold references, I'm still unsure why
you aren't storing pointers to those objects in the vector. Then all you
have to do is traverse the vector, using the pointers to access the objects
which hold the references. It's mostly just a difference between using "."
and using "->" to access the obects' members.

(Naturally, you have to manage the creation/destruction of the objects
appropriately when using pointers, but a good smart pointer such as Boost
provides will help there, too.)

-Howard

Jun 30 '06 #24

This discussion thread is closed

Replies have been disabled for this discussion.