5

I have a class with a member which is not changed by the methods of the class, so I marked it as const. My problem is that I was using the default assignment operator just like a copy constructor in order to avoid multiple declarations. But in this case the assignment operator is not automatically generated, so I get some compiler errors: 'operator =' function is unavailable. This seems like that there is no real life scenario where const class members can be actually used (e.g. have you seen any const member in the STL code?).

Is there any way to fix this, beside removing the const?

EDIT: some code

class A
{
public :
   const int size;
   A(const char* str) : size(strlen(str)) {}
   A() : size(0) {}
};


A create(const char* param)
{
    return A(param);
}


void myMethod()
{
    A a;

    a = create("abcdef");
    // do something

    a = create("xyz");
    // do something
}
Andrei Bozantan
  • 3,781
  • 2
  • 30
  • 40
  • I edited the title to something that I think more closely describes what you meant to ask, and will encourage more useful answers. If you disagree, feel free to change it back. – Crashworks Jan 16 '12 at 07:46

4 Answers4

3

Here's your misconception which is causing this issue:

[..] which is not changed by the methods of the class

The member variable is changed by a method of your class, the assignment operator. Including the one synthesized by the compiler. If you mark a member variable as const, this expresses that this variable will (should not!) change its value during the lifetime of the object. So clearly, assigning a new value to the object violates this statement. So if you indeed don't want the member to change, just don't make it const.

Frerich Raabe
  • 90,689
  • 19
  • 115
  • 207
2

const members are ideal in many, many cases. of course, there is the obvious case where a value should not or must not change, but it's also an important restriction for optimization and concurrency -- not every type needs or should have an assignment operator.

if the member needs the behavior of assignment, then the variable must not be const.

when the value/member must not mutate or be mutated by this, it's clearer to provide a separate interface for the variable members (or even a subtype->composition in more complex cases):

class t_text {
public:
// ...
public:
    void setString(const std::string& p);
private:
    const t_text_attributes d_attributes;
    std::string d_string;
};

therefore, my suggestion is to hide the assignment operator, and to make the 'mutable chunk' or member set-able for clarity:

text.setString("TEXT"); // << Good: What you read is what happens.
text = otherText; // << Bad: Surprise - attributes don't actually change!
justin
  • 104,054
  • 14
  • 179
  • 226
  • 4
    Optimization and concurrency are about the least important reasons for using `const` I can think of. I'd say it's more important to keep you from doing stupid things by forcing you to think (or at least force you to feel a little guilty for having to cast away constness). – Frerich Raabe Jan 16 '12 at 08:11
  • @Frerich perhaps it was a mistake on my part, but using `const` for the most obvious reason was assumed. I will update that to avoid confusion. – justin Jan 16 '12 at 08:26
2

You cannot have a const member and support assignment, at least not assignment with the expected semantics. const is, logically, a promiss that the member will never change, and assignment is (implicitly, in the minds of most people) a promiss that all data members will take the values of the members of the right hand side (which normally means changing). There's a very definite conflict between these two promisses.

Of course, a lot of types shouldn't support assignment to begin with; for types that don't support assignment, there's no problem declaring a data member const. On the whole, however, I've found const a lot less useful here; const is part of a contract, and data members are not usually part of the external contract of the class. (But a lot depends—if the data member is public or protected, then the fact that it is immutable could be part of the external contract. And of course, there's nothing wrong with expressing internal class invariants in language constructs, either.)

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • 2
    "You cannot" -- well, you can, but then you do have to define a custom assignment. For example, a logically assignable object allocated by X could contain a const pointer to X, to help with asking X to deallocate that object. Such a thing might solve some problems imposed by an existing framework, say. The pointer would be constant over the lifetime of the object, and not exposed as part of the logical object state. I.e. it would not be part of the externally assignable state. Cheers & hth., – Cheers and hth. - Alf Jan 16 '12 at 11:56
1

Yes, you can override the assignment operator.

Because you're using the default one, the compiler will try to copy the const members also. Which is illegal, since it's const.

class A
{
private:
   const int a;
public :
   A() : a(0) {}
   A& operator = (const A& other) {return *this;}
};

int main()
{
   A a;
   A b;
   a = b; //this is legal if operator = is declared
}
Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 2
    So the price of const members is that you can provide an assignment operator, but only a broken one? – UncleBens Jan 16 '12 at 07:48
  • 1
    @UncleBens why is this broken? It's not, it's just not modifying the `const` member... which should make sense, right? – Luchian Grigore Jan 16 '12 at 07:50
  • 1
    @UncleBens: Given that the `const` member on the lhs is likely to be the same as on the `rhs` as it's set only in the constructor, there's no point in copying it. If it's initialised differently in different constructors, then you may wish to reconsider your design! – johnsyweb Jan 16 '12 at 07:53
  • 1
    The "price" of const members is that if you want assignment, you need to define the assignment operator yourself. I consider that a feature. – Simon Richter Jan 16 '12 at 07:57
  • 2
    @Johnsyweb: If the const member is going to be the same for all instances (such as in the given example), why is it a non-static member? - Perhaps a more realistic example would be `A::A(int init_value): a(init_value)`. Now what sense would (any) operator= overload make? – UncleBens Jan 16 '12 at 08:06
  • what if we have a const_cast hack for the const member ? Will that make sense ? – Jagannath Jan 16 '12 at 08:10
  • 1
    @Jagannath no `const_cast` hacking, please! http://stackoverflow.com/questions/5008541/how-to-call-a-non-const-function-within-a-const-function-c/5008581#5008581 – justin Jan 16 '12 at 08:11
  • to clarify on the link for all: the answers which said you *could* `const_cast` while discouraging it have received almost as many downvotes as upvotes. – justin Jan 16 '12 at 08:21
  • 1
    This is not `overidding` this is `overloading`. `virtual` keyword is necessary for saying `overidding`. – Alok Save Jan 16 '12 at 08:45