12

If so, why? Why doesn't it use the copy constructor of the value type?

I get the following error:

/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/vector.tcc: In member functio
n `ClassWithoutAss& ClassWithoutAss::operator=(const ClassWithoutAss&)':
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/vector.tcc:238:   instantiate
d from `void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterato
r<typename _Alloc::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp =
ClassWithoutAss, _Alloc = std::allocator<ClassWithoutAss>]'
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_vector.h:564:   instantia
ted from `void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = Class
WithoutAss, _Alloc = std::allocator<ClassWithoutAss>]'
main.cpp:13:   instantiated from here
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/vector.tcc:238: error: non-st
atic const member `const int ClassWithoutAss::mem', can't use default assignment
 operator

running g++ main.cpp on the following code:

/*
 * ClassWithoutAss.h
 *
 */

#ifndef CLASSWITHOUTASS_H_
#define CLASSWITHOUTASS_H_

class ClassWithoutAss
{

public:
    const int mem;
    ClassWithoutAss(int mem):mem(mem){}
    ClassWithoutAss(const ClassWithoutAss& tobeCopied):mem(tobeCopied.mem){}
    ~ClassWithoutAss(){}

};

#endif /* CLASSWITHOUTASS_H_ */

/*
 * main.cpp
 *
 */

#include "ClassWithoutAss.h"
#include <vector>

int main()
{
    std::vector<ClassWithoutAss> vec;
    ClassWithoutAss classWithoutAss(1);
    (vec.push_back)(classWithoutAss);

    return 0;
}
4
  • 16
    +1 if only for ClassWithoutAss. Commented Jul 17, 2010 at 18:28
  • 2
    Why do you bracket the vec.push_back ... it won't cause any issues but seems a tad unnecessary ... Commented Jul 17, 2010 at 18:56
  • 1
    Is that an "ass" as in "donkey"? Commented Jul 17, 2010 at 21:22
  • I guess it's just Cl then... Commented Jul 21, 2018 at 5:13

2 Answers 2

13

The C++03 standard says elements must be copy-constructible and copy-assignable to be used in a standard container. So an implementation is free to use whichever it wants.

In C++0x, these requirements are put on a per-operation basis. (In general, elements must be move-constructible and move-assignable.)

To get what you want, you should use a smart pointer like shared_ptr (from either Boost, TR1, or C++0x), and completely disable copy-ability:

class ClassWithoutAss
{
public:
    const int mem;

    ClassWithoutAss(int mem):mem(mem){}
    // don't explicitly declare empty destructors

private:
    ClassWithoutAss(const ClassWithoutAss&); // not defined
    ClassWithoutAss& operator=(const ClassWithoutAss&); // not defined
};

typedef shared_ptr<ClassWithoutAss> ptr_type;

std::vector<ptr_type> vec;
vec.push_back(ptr_type(new ClassWithoutAss(1)));

Pointers can be copied just fine, and the smart pointer ensures you don't leak. In C++0x you can do this best with a std::unique_ptr, taking advantage of move-semantics. (You don't actually need shared semantics, but in C++03 it's easiest as it stands.)

Sign up to request clarification or add additional context in comments.

5 Comments

I believe you, but can you explain why pointers rather than defining my own operations? Faster push_backs? So I don't waste my time defining operations? I'll have to look into move/share semantics. Thanks GMan. I only have these problems with your help. ;)
@drenami: What do you mean? I used pointers because you want to have your class in the container, but you can't do it directly. One abstraction above that is a pointer to your class, rather than the class itself. (And the smart pointers just to prevent leaks.)
But I could if I defined an assignment operator right? So my question is pro/cons of the two designs--one without assignment/using pointers, one defining assignment. Both are options because I can write ClassWithAss.
@drenami: I see. The thing is, your assignment operator would have to just do nothing, which is about as far from "assigning" as it gets. While there are certainly ways to hack around the problem, the more correct solution would be to recognize the design consequences. That is, if a class has a const member, it doesn't make conceptual sense to copy or assign it; that's why I recommend disabling those operations entirely. However, another way to go is to get rid of the const part, allowing real assignments to occur. (Obviously this choice depends on your big picture, which I don't know.)
This answer is out of date -- as of C++11, standard containers all use copy/move constructors for non-assignment operations (like push_back), so do not require assignable objects unless you actually assign the container or a container element.
5

The problem here is that types in a container must be assignable.

Because you do not define an assignment operator for your class the compiler will generate one for you. The default assignment operator will look like this:

ClassWithoutAss& operator=(ClassWithoutAss const& rhs)
{
    mem = copy.mem;
    return *this;
}
// The compiler generated assignment operator will copy all members
// using that members assignment operator.

In most situations this would work. But the member mem is a const and thus unassignable. Therefore compilation will fail when it tries to generate the assignment operator.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.