From: Miles Bader on
If I have the following test file, x.cc:

#include <vector>

class X
{
public:
X (const int &_i) : i (_i) { }
X (const X &x) : i (x.i) { }
#if 0
X &operator= (const X &x)
{
if (&x != this)
new (this) X (x.i);
return *this;
}
#endif
const int &i;
};

int test ()
{
std::vector<X> xv;

int i;
xv.push_back (X (i));
}

I get an error during compilation, like:

g++ -c -o x.o x.cc
x.cc: In member function 'X& X::operator=(const X&)':
x.cc:4: instantiated from 'void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp = X, _Alloc = std::allocator<X>]'
/usr/include/c++/4.4/bits/stl_vector.h:741: instantiated from 'void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = X, _Alloc = std::allocator<X>]'
x.cc:23: instantiated from here
x.cc:4: error: non-static reference member 'const int& X::i', can't use default assignment operator

Changing the "#if 0" to "#if 1" to define operator= makes things work.

I understand the immediate reason for the error: the g++ vector
implementation does indeed seem to call operator= on vector elements for
push_back, and in this case, the compiler-synthesized method isn't good
enough.

But it somehow seems wrong that it's using operator= at all; shouldn't a
copy-constructor be enough?

Looking at the g++ STL headers, it seems like the problem is that it's
defining push_back in terms of insertion, and for the latter, you need
operator= to move elements subsequent elements to make room for a new
element. However in the case of push_back, that's really unnecessary,
and no copying of objects other than copy-constructing into new memory
when the vector's underlying storage is reallocated should be need.

Opinions? Is the error here reasonable?

Thanks,

-Miles

--
Happiness, n. An agreeable sensation arising from contemplating the misery of
another.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Goran on
On Feb 1, 7:04 am, Miles Bader <mi...(a)gnu.org> wrote:
> If I have the following test file, x.cc:
>
> #include <vector>
>
> class X
> {
> public:
> X (const int &_i) : i (_i) { }
> X (const X &x) : i (x.i) { }
> #if 0
> X &operator= (const X &x)
> {
> if (&x != this)
> new (this) X (x.i);
> return *this;
> }
> #endif
> const int &i;
> };
>
> int test ()
> {
> std::vector<X> xv;
>
> int i;
> xv.push_back (X (i));
> }
>
> I get an error during compilation, like:
>
> g++ -c -o x.o x.cc
> x.cc: In member function �X& X::operator=(const X&)�:
> x.cc:4: instantiated from �void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp = X, _Alloc = std::allocator<X>]�
> /usr/include/c++/4.4/bits/stl_vector.h:741: instantiated from �void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = X, _Alloc = std::allocator<X>]�
> x.cc:23: instantiated from here
> x.cc:4: error: non-static reference member �const int& X::i�, can't use default assignment operator
>
> Changing the "#if 0" to "#if 1" to define operator= makes things work.
>
> I understand the immediate reason for the error: the g++ vector
> implementation does indeed seem to call operator= on vector elements for
> push_back, and in this case, the compiler-synthesized method isn't good
> enough.

I would guess that in this case compiler can't emit operator= at all,
because you have a reference member.

IOW, I think that your class is not copy-able because it has a
reference member, and that is the reason why you are using ugly
"construction in operator=" trick. That is almost always unwarranted
and whoever taught you this is wrong. If you want copying, you could
just as well be using a pointer there (but expose a reference-like
semantics to users if that's what you need). There is very little, if
anything, to to gain in using a reference there.


>
> But it somehow seems wrong that it's using operator= at all; shouldn't a
> copy-constructor be enough?
>
> Looking at the g++ STL headers, it seems like the problem is that it's
> defining push_back in terms of insertion, and for the latter, you need
> operator= to move elements subsequent elements to make room for a new
> element. However in the case of push_back, that's really unnecessary,
> and no copying of objects other than copy-constructing into new memory
> when the vector's underlying storage is reallocated should be need.
>
> Opinions? Is the error here reasonable?

Yes, it's reasonable, because push_back might need to re-allocate
storage, at which point it needs to copy existing elements to new
place. So IMO, the need to copy can be avoided only by dropping part
of push_back functionality.

Goran.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Tony Delroy on
On Feb 1, 3:04 pm, Miles Bader <mi...(a)gnu.org> wrote:
> Looking at the g++ STL headers, it seems like the problem is that it's
> defining push_back in terms of insertion, and for the latter, you need
> operator= to move elements subsequent elements to make room for a new
> element. However in the case of push_back, that's really unnecessary,
> and no copying of objects other than copy-constructing into new memory
> when the vector's underlying storage is reallocated should be need.
>
> Opinions? Is the error here reasonable?

I think it's better for the compilation to fail. Bigger picture:
library developers need to be able to say "input: vector of T", and
know they can do all the things to the vector that a vector is meant
to support. Having half-baked vectors around that will break when
someone re-implements some algorithm, using other parts of the vector
interface, is unacceptable at the enterprise scale. The interface is
not intended to be "fat", with code checking which vector operations a
particular instantiation will support....

Cheers,
Tony


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Daniel Krügler on
On 1 Feb., 07:04, Miles Bader <mi...(a)gnu.org> wrote:
> If I have the following test file, x.cc:
>
> #include <vector>
>
> class X
> {
> public:
> X (const int &_i) : i (_i) { }
> X (const X &x) : i (x.i) { }
> #if 0
> X &operator= (const X &x)
> {
> if (&x != this)
> new (this) X (x.i);
> return *this;
> }
> #endif
> const int &i;
> };
>
> int test ()
> {
> std::vector<X> xv;
>
> int i;
> xv.push_back (X (i));
> }
>
> I get an error during compilation, like:
>
> g++ -c -o x.o x.cc
> x.cc: In member function �X& X::operator=(const X&)�:
> x.cc:4: instantiated from �void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp = X, _Alloc = std::allocator<X>]�
> /usr/include/c++/4.4/bits/stl_vector.h:741: instantiated from �void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = X, _Alloc = std::allocator<X>]�
> x.cc:23: instantiated from here
> x.cc:4: error: non-static reference member �const int& X::i�, can't use default assignment operator
>
> Changing the "#if 0" to "#if 1" to define operator= makes things work.
>
> I understand the immediate reason for the error: the g++ vector
> implementation does indeed seem to call operator= on vector elements for
> push_back, and in this case, the compiler-synthesized method isn't good
> enough.
>
> But it somehow seems wrong that it's using operator= at all; shouldn't a
> copy-constructor be enough?
>
> Looking at the g++ STL headers, it seems like the problem is that it's
> defining push_back in terms of insertion, and for the latter, you need
> operator= to move elements subsequent elements to make room for a new
> element. However in the case of push_back, that's really unnecessary,
> and no copying of objects other than copy-constructing into new memory
> when the vector's underlying storage is reallocated should be need.
>
> Opinions? Is the error here reasonable?

Yes and no ;-)

According to the requirements of the C++03 standard the error
message is reasonable, because the fundamental requirement
exists, that any value type of a container has to satisfy the
CopyConstructible and Assignable requirements
([lib.container.requirements]/3).

In C++0x there is some redrafting in progress that will define
the requirements more specifically. In case of push_back
provided with an rvalue (as in your example), the necessary
requirement should be that the value type satisfies the
MoveConstructible requirements (which is a subset of
CopyConstructible).

HTH & Greetings from Bremen,

Daniel Kr�gler


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Bart van Ingen Schenau on
On Feb 1, 7:04 am, Miles Bader <mi...(a)gnu.org> wrote:
> If I have the following test file, x.cc:
>
> #include <vector>
>
> class X
> {
> public:
> X (const int &_i) : i (_i) { }
> X (const X &x) : i (x.i) { }
> #if 0
> X &operator= (const X &x)
> {
> if (&x != this)
> new (this) X (x.i);
> return *this;
> }
> #endif
> const int &i;
> };
>
> int test ()
> {
> std::vector<X> xv;
>
> int i;
> xv.push_back (X (i));
> }
>
> I get an error during compilation, like:
>
> g++ -c -o x.o x.cc
> x.cc: In member function �X& X::operator=(const X&)�:
> x.cc:4: instantiated from �void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp = X, _Alloc = std::allocator<X>]�
> /usr/include/c++/4.4/bits/stl_vector.h:741: instantiated from �void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = X, _Alloc = std::allocator<X>]�
> x.cc:23: instantiated from here
> x.cc:4: error: non-static reference member �const int& X::i�, can't use default assignment operator
>
> Changing the "#if 0" to "#if 1" to define operator= makes things work.
>
> I understand the immediate reason for the error: the g++ vector
> implementation does indeed seem to call operator= on vector elements for
> push_back, and in this case, the compiler-synthesized method isn't good
> enough.
>
> But it somehow seems wrong that it's using operator= at all; shouldn't a
> copy-constructor be enough?
>
> Looking at the g++ STL headers, it seems like the problem is that it's
> defining push_back in terms of insertion, and for the latter, you need
> operator= to move elements subsequent elements to make room for a new
> element. However in the case of push_back, that's really unnecessary,
> and no copying of objects other than copy-constructing into new memory
> when the vector's underlying storage is reallocated should be need.
>
> Opinions? Is the error here reasonable?

The error is very reasonable, because
1- The standard states that the element-types used for std::vector
must be copy-constructable *and* assignable.
2- The standard describes the operation of push_back in terms of
insert

So, without the user defined operator=, your type is not assignable
and thus does not meet the minimum requirements for being used as
element-type in a std::vector. Doing so anyway results in a diagnostic
at best and UB at worst.
And, as the operation of v.push_back(x) is equivalent to v.insert(v.end
(), x), it is only logical to implement one in terms of the other.

>
> Thanks,
>
> -Miles
>
Bart v Ingen Schenau


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

 |  Next  |  Last
Pages: 1 2
Prev: const as default
Next: CRTP and typedef