Readonly variables

Jun 2, 2010 at 10:40pm
Hi,

now this has always been the single most annoying thing about C++ to me and I would really love to have a solution for it.

Common case: You have a variable in a class that can be read, but should not be edited from outside this class. How do you make the variable easily accessible on the one hand and secure it from editing on the other.

Now as far as I know, there are two ways to implement this:
1) (this is most common)
1
2
3
4
5
6
7
8
class cls
{
private:
int foo;

public:
__forceinline int GetFoo() {return foo};
}

Pros: The method is secure

2)
1
2
3
4
5
class cls
{
public:
int foo;
}

Pros: The method is fast and needs little code

So why would someone implement the second approach? Well first of all it looks way better. The class definition isn't bloated with GetThis() and GetThat() and also when using foo somewhere else it can be directly accessed like this:

1
2
3
4
cls c;
... = c.foo * c.foo + ...
... = c.foo + ...
...


instead of like this:

1
2
3
4
cls c;
... = c.GetFoo() * c.GetFoo() + ...
... = c.GetFoo() + ...
...


or like this:

1
2
3
4
5
cls c;
int cfoo = c.GetFoo();
... = cfoo * cfoo + ...
... = cfoo + ...
...


Just imagine having tons of read-only variables like foo. Also even when using __forceinline, which should already be one level above inline (being just some kind of a recommendation to the compiler), I am still not 100% convinced that c.GetFoo() can be as fast as foo.

Therefore I have used the second approach for a long time now, but on larger programs even I (as the author of my own code) lose the plot on which variables can be edited directly and which not.

Currently I am using a macro like this:

1
2
3
4
#define READONLY(type, publicvar, localvar, getfunc)	protected: type localvar; public: __forceinline type getfunc() {return localvar;}; \
							__declspec(property(get=getfunc)) type publicvar;

READONLY(int, foo, myfoo, GetFoo);


But again I face some drawbacks:
1) My local variable has to be named differently (here myfoo).
2) I have to declare a function, that I never directly call (here GetFoo).
3) The declaration itself still looks bloated.

In conclusion the issue may look trivial at first, but I'm sure I'm not the only one getting constant headaches about it.
Jun 2, 2010 at 10:44pm
Consider this:

1
2
3
4
5
6
7
8
class cls
{
private:
int foo;

public:
  const int& GetFoo() {return foo};
}


It should be as efficient as this:


1
2
3
4
5
class cls
{
public:
    int foo;
}


Without the dangers.
Last edited on Jun 2, 2010 at 10:45pm
Jun 2, 2010 at 10:50pm
const int& GetFoo() {return foo}; is definitely not more efficient than int GetFoo() const {return foo};
To clarify:
int GetFoo() const {return foo}; has zero overhead, it will generate the same code as if foo were public and you were accessing it directly.
Last edited on Jun 2, 2010 at 10:52pm
Jun 3, 2010 at 8:07am
Thank you for the quick answers. I am really lazy when it comes to flagging functions as constant. I thought this only makes accessing member functions of constant variables possible (with out any performance advantages).
Jun 3, 2010 at 8:49am
Doesn't
int GetFoo() const {return foo};
copy foo and return it? Because it will have the same effect as initialization:
int return_value = foo;
And this copies foo into another variable. However, If you are not changing the return value you get from the function and you are not using the class over other threads, I understand that a compiler might optimize it to be just as fast as:
const int& GetFoo() {return foo};
But that would be a very difficult job and I therefor think it won't be optimized like that in most cases.
Jun 3, 2010 at 9:56am
@magnificence7 I believed as you that returning the reference would be more efficient than returning the copy.

However, it appears that Athar is correct. I have done a number of tests and it appears that when under optimisation the compiler optimises away the differences to leave identical code in both cases.

I think that, because the object itself can not be modified, the compiler simply treats the copy return as a reference return. The point being that what is returned will only be copied at some point anyway, if it gets assigned to another variable or used in an expression or passed as a parameter. So the compiler is able maintain what we would imagine is a copy, as a reference.

At least, that is what I *think* might be going on.

Without optimisation I found the copy is one instruction longer than the reference. But in that scenario, *both* were MUCH less efficient than the simple member access due to the massive overhead of the function call.
Jun 4, 2010 at 10:49am
Did anyone test the whole thing with inline?
Jun 4, 2010 at 1:43pm
1
2
3
4
5
6
class Foo {
   public:
      int GetFoo() const { return foo; }
};

int x = f.GetFoo();


foo will be returned in a register. That register will then get stored into x, assuming
that the compiler does not optimize away x into a register itself. This is as fast as it
gets, unless your processor supports instructions that support two sequential memory operations (doubtful).

Whether or not the compiler chooses to inline a method is really up to the compiler -- you
have no control over it. You can only recommend the compiler to inline a method by using
the inline keyword.

This means that you should not write your code to work around an idiosyncrasy in your
compiler. Use inline. Most likely the compiler will inline it since it is so simple.

Topic archived. No new replies allowed.