Any problems with this C ++ aperture reference interface idiom?

I converted the structure to a class so that I could apply the setter interface to my variables.
However, I did not want to change all instances where the variable was read. So I converted this:

struct foo_t { int x; float y; }; 

:

 class foo_t { int _x; float _y; public: foot_t() : x(_x), y(_y) { set(0, 0.0); } const int &x; const float &y; set(int x, float y) { _x = x; _y = y; } }; 

I am interested in this because it seems to be modeling the C # idea for read-only public properties.
It compiles fine, and I have not seen any problems yet.

Besides the const reference binding pattern in the constructor, what are the lower bounds of this method?
Any weird issues with an alias?
Why haven't I seen this idiom before?

+6
c ++ public const accessor
source share
4 answers

This is a problem with the alias, because you specify a link to the internal data foo_t , it is possible that the code external to the foo_t object keeps links in its data for the lifetime of the object. Consider:

 foo_t* f = new foo_t(); const int& x2 = f->x; delete f; std::cout << x2; // Undefined behavior; x2 refers into a foo_t object that was deleted 

Or, even simpler:

 const int& x2 = foo_t().x; std::cout << x2; // Undefined behvior; x2 refers into a foo_t object that no longer exists 

These are not particularly realistic examples, but this is a potential problem when an object provides or returns a link to its data (public or private). Of course, it is possible to attach to the foo_t object as soon as possible outside of his life, but it can be harder to miss or do it by accident.

Not that this is an argument against what you are doing. Actually, I used this template before (for another reason), and I don’t think that something is inherently wrong with it, except for the lack of encapsulation that you seem to recognize. The above problem is what you need to know about.

+5
source share

One of the problems is that your class is no longer copied or assigned, so it cannot be stored in C ++ containers, such as vectors. Another is that experienced C ++ programmers supporting your code will look at it and exclaim "WTF !!" very loud that is never good.

+11
source share

You can also do something like this that works for built-in types: (Sorry if this code snippet contains errors, but you get the idea)

 template <typename T, typename F> class read_only{ typedef read_only<T, F> my_type; friend F; public: operator T() const {return mVal;} private: my_type operator=(const T& val) {mVal = val; return *this;} T mVal; }; class MyClass { public: read_only <int, MyClass> mInt; void MyFunc() { mInt = 7; //Works } }; AnyFunction(){ MyClass myClass; int x = myClass.mVal; // Works (okay it hasnt been initalized yet so you might get a warning =) myClass.mVal = 7; // Error } 
+2
source share

Your approach is not flexible. When you have getter / setter for each variable, that means you don’t have to rewrite your set method if you add something to your class.

This is not good, because you cannot use const and non-const getters (which are rarely used, but can sometimes be useful).

You cannot copy links, so your class is not copied.

In addition, referring to the initialization in your class, this is additional memory, and if we are talking about, for example, a vertex class (although I think it should not be a class in fact), this can be a disaster.


[Everything that follows is completely subjective]

The goal of getters and setters, in my opinion, is not a simple modification, but to encapsulate a sequence of actions that leads to a change in value or returns a value (which we consider as a visible result).

The personal structure in the case of your example will be more efficient, because it wraps the POD data and logically "structures" it.

0
source share

All Articles