2

In C++, how can I accept a variable by reference, then store it on the object instance - so that I can modify it any time I want?

The variable in question is a volatile unsigned char currently.

An example class to clarify:

class SomeClass {
    public:
        SomeClass(volatile unsigned char &value);
        void changeIt();
    private:
        volatile unsigned char _value;
}

SomeClass::SomeClass(volatile unsigned char &value) {
    _value = value;
}

void SomeClass:changeIt() {
    _value++;
}

What I now want is to let the caller be able to pass this variable, and let me change it whenever I need. The reason I need this is that the passed variable is special (it maps to a CPU registry on a microcontroller).

I want to be able to do this:

SomeClass myClass(PORTB);

// PORTB is the same

myClass.changeIt();

// PORTB is changed

I'm pulling my hair out trying to figure this out (I come from the Java world... :)

frodeborli
  • 1,537
  • 1
  • 21
  • 30
  • 4
    By having a *reference* member rather than a *value* member, and using an initializer list. (or I completely misunderstood the question). – WhozCraig Jun 15 '14 at 22:31
  • @WhozCraig It seems I had to have an initializer list (which I didn't know existed just moments ago...) :-) – frodeborli Jun 15 '14 at 22:40
  • 3
    Get used to them, as they're required for `const` and `reference` members, as well as implementing proper copy/move semantics of non-trivial objects. Study up on them; its worth it to do now rather than later. – WhozCraig Jun 15 '14 at 22:42
  • 1
    Consider making the class take a pointer rather than a reference – M.M Jun 15 '14 at 22:54
  • @MattMcNabb In this case, there are no real benefits to using pointers and references are prettier, API wise. The Arduino community is quite focused on making libraries that new programmers can benefit from quickly. – frodeborli Jun 15 '14 at 23:15

1 Answers1

3

You need to declare field in the class as a reference (by keeping non-ref, you're creating a copy for each instance):

class SomeClass {
    public:
        SomeClass(volatile unsigned char &value);
        void changeIt();
    private:
        volatile unsigned char& _value;
}

The only thing now is the need to store the reference before constructor body is executed, and you can do that in the initializer list:

SomeClass::SomeClass(volatile unsigned char &value): 
  _value(value)
{
}

Everything else now should work (but take the great comments from DaoWen in the account).

Nemanja Boric
  • 21,627
  • 6
  • 67
  • 91
  • *"Everything else now should work."* — Actually, `_value++` isn't guaranteed to be an atomic operation, so that might not be true... – DaoWen Jun 15 '14 at 22:35
  • I guess with `volatile` in C++, you just can't be sure :-). – Nemanja Boric Jun 15 '14 at 22:36
  • All `volatile` does is tell the compiler it must always read the value from memory (can't use a cached value from a register). A compound read-and-update operation like `_value++` isn't atomic in Java either. Also note how that means declaring `SomeClass(volatile unsigned char &value);` and `SomeClass(unsigned char &value);` would yield identical behavior in this case since `value` is only used as a pointer to initialize `_value` (the pointed-to value is never read). – DaoWen Jun 15 '14 at 22:37
  • Note that `volatile` in java means that access to the variable acts as though it is enclosed in a synchronized block, so `_value++` should be atomic (if I'm not mistaken). Also, in `C++` it tell the compiler that he can't presume anything about this variable (which important for the optimizations) - it could be in the some counter, for example, or it could be changed outside the program (like in a some interface register), it doesn't need to be in the memory. Also, good note about constructor argument! – Nemanja Boric Jun 15 '14 at 22:39
  • Well, everything did work! :-) @DaoWen Everything on my microcontroller is atomic operations, and the ++ was an example. I plan to change only a single bit in that variable. – frodeborli Jun 15 '14 at 22:39
  • *Note that volatile in java means that access to the variable acts as though it is enclosed in a synchronized block, so _value++ should be atomic (if I'm not mistaken).* — You're mistaken. This is one reason why they added the AtomicInteger class (which has an atomic increment method). See [this question](http://stackoverflow.com/questions/15287419) for how integer increment is not atomic in Java. – DaoWen Jun 15 '14 at 22:42
  • Oh, thanks, I see. This is also a good thread: http://stackoverflow.com/questions/19744508/volatile-vs-atomic – Nemanja Boric Jun 15 '14 at 22:46
  • @frodeborli - If you know that your compiler generates an atomic instruction for `_value++` then you're probably OK. However, if you ever switch compilers or targets you might have a problem. It's probably safer to use an [atomic compiler intrinsic](https://gcc.gnu.org/onlinedocs/gcc-4.5.0/gcc/Atomic-Builtins.html), or [`std::atomic`](http://www.cplusplus.com/reference/atomic/) if you have C++11 support. – DaoWen Jun 15 '14 at 22:47
  • @DaoWen My 8-bit microcontroller does not multitask/thread, and the code is a hardware specific library I made. But I get the point. :) More interesting is that they have closed the question, as off topic. – frodeborli Jun 23 '14 at 23:51