Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Name for a public const and private writable attribute?

Tags:

c++

Programming in C++, I often want to give the user of a class read-only access to an attribute, and the class itself read-write access. I hate XxxGet() methods, so I often use a public const & to a private attribute, like this:

class counter {
  private:
     int _count;

  public:
     const int & count;

     counter : _count( 0 ), count( _count ){}

     void inc( void ){ _counter++; }
};

Is there a common name for this trick?

like image 405
Wouter van Ooijen Avatar asked Sep 15 '11 14:09

Wouter van Ooijen


People also ask

What is const keyword in C++?

The const keyword specifies that a variable's value is constant and tells the compiler to prevent the programmer from modifying it.

What does const after a function mean C++?

The const member functions are the functions which are declared as constant in the program. The object called by these functions cannot be modified. It is recommended to use const keyword so that accidental changes to object are avoided.

What is const int in C?

Integer constant in C is a data type that is represented by const int . const int is capable of storing an integer in decimal, octal, and hexadecimal bases. The value to const int is assigned only when it is declared and cannot be changed afterward.


3 Answers

My personal name for that trick would be bad idea.

I would avoid the approach that you are following, as it incurs extra unneeded cost. If you add accessors they can be inlined as needed, with the only penalty of having to type an extra pair of parentheses:

class counter {
    int _count;
public:
    counter() : _count() {}
    int count() const { return _count; }
    void inc() { ++_count; }
};

The main difference is that in your solution you are incrementing the size of the object by one reference (for most implementations this means pointer), and then each access requires an extra indirection. On the other hand, with the accessor, the actual variable is used, the function will be optimized away (inlined, and resolved to a single read to the variable).

As of a proper name for that type of construct, well, I have never seen your particular construct in C++, but if you consider other languages, that is the basic concept of a property in C#, where you can make the getter public and the setter private.

EDIT: I guess that bad idea can be misinterpreted as just a personal opinion (which it is), but consider the side effects of that design:

Because of the reference in the object, you inhibit the implicit definition of the assignment operator. Much worse, the copy constructor will compile but not work as expected:

// consider the implementation with the const reference
counter c1;
counter c2( c1 );          // compiles, so it must work
c2.inc();
std::cout << c2.count;   // outputs 0
// c2 = c1;              // error: well, at least this does not compile!

The problem is that the compiler generated copy constructor will make the count reference in c2 refer to the same int that the count reference in c1 refers to, which might lead to hard-to-find subtle issues in your code that are actually quite hard to debug.

like image 115
David Rodríguez - dribeas Avatar answered Sep 21 '22 15:09

David Rodríguez - dribeas


Edit

Just now I thought of a name that could be considered the same pattern. Though not typically used for member variables.

There could actually be a name for this, as has been made popular by the Boost Tuple library as well as the TR1/C++11 implementations:

Tieing

Typical example:

 tuple<int> tie(ref(some_var));
 // or shorter:
 auto tied = tie(var1, var2, var3);

Assignment complications

The closest name for this (anti?) pattern I could _immediately think of before, is: pointer or reference aliasing. It is not a very good idea for many reasons, some of which have been mentioned

  • class layout + size
  • copy/assignment semantics
  • compiler optimizations: the compiler will shun from making assumptions about the value of (register-allocated) variables when it knows references could point to the same memory location.

In addition to the points David makes, the compiler will be unable to generate default

  • semantically valid copy constructor
  • assignment operator
  • move assignment operator

for your class now that contains references. Note also that your class can't possibly be POD anymore

like image 27
sehe Avatar answered Sep 20 '22 15:09

sehe


A number of others have already condemned this idea, and I (mostly) tend to agree with them. Although quite a few people probably dislike it (at least) as much, if I was going to support something on this order, I'd do something like this:

class counter { 
    int count_;
public:
    counter(int init=0) : count_(init) {}
    operator int() const { return count_; }
    void inc() { ++count_; }
};

The one problem with this is one that's shared with implicit conversions in general: that the implicit conversion can happen even when you don't want it to. OTOH, the fact that it's a user-supplied conversion actually eliminates many of the problems -- only one implicit conversion will happen automatically in any given situation, so (for example) the fact that you've supplied a conversion to int will not mean that a counter with a value of 0 can be implicitly converted from a counter to an int to a (null) pointer to T, because that would involve two implicit conversions.

There are times this can cause a problem anyway, in which case (as of C++11) you can make the conversion operator explicit, so it'll only happen when/if the user does an explicit conversion like:

counter t;

int x = t;  // allowed by code above, but not with `explicit` conversion operator.

int y = static_cast<int>(t);    // allowed with `explicit` conversion operator.
like image 40
Jerry Coffin Avatar answered Sep 17 '22 15:09

Jerry Coffin