Search

8.14 — Anonymous variables and objects

In some cases, we need a variable only temporarily. For example, consider the following situation:

In the add() function, note that the sum variable is really only used as a temporary placeholder variable. It doesn’t contribute much -- rather, it’s only function is to transfer the result of the expression to the return value.

There is actually an easier way to write the add() function using an anonymous variable. An anonymous variable is a variable that is given no name. Anonymous variables in C++ have “expression scope”, meaning they are destroyed at the end of the expression in which they are created. Consequently, they must be used immediately!

Here is the add() function rewritten using an anonymous variable:

When the expression x + y is evaluated, the result is placed in an anonymous, unnamed variable. A copy of the anonymous variable is then returned to the caller by value.

This works not only with return values, but also with function parameters. For example, instead of this:

We can write this:

In this case, the expression 5 + 3 is evaluated to produce the result 8, which is placed in an anonymous variable. A copy of this anonymous variable is then passed to the printValue() function, which prints the value 8.

Note how much cleaner this keeps our code -- we don’t have to litter the code with temporary variables that are only used once.

Anonymous class objects

Although our prior examples have been with built-in data types, it is possible to construct anonymous objects of our own class types as well. This is done by creating objects like normal, but omitting the variable name.

In the above code, Cents(7) will create an anonymous Cents object, initialize it with the value 7, and then destroy it. In this context, that isn’t going to do us much good. So let’s take a look at an example where it can be put to good use:

Note that this example is very similar to the prior one using integers. In this case, our main() function is passing a Cents object (named cents) to function print().

We can simplify this program by using anonymous variables:

As you’d expect, this prints:

6 cents

Now let’s take a look at a slightly more complex example:

In the above example, we’re using quite a few named Cents values. In the add() function, we have a Cents value named sum that we’re using as an intermediary value to hold the sum before we return it. And in function main(), we have another Cents value named sum also used as an intermediary value.

We can make our program simpler by using anonymous values:

This version of add() functions identically to the one above, except it uses an anonymous Cents value instead of a named variable. Also note that in main(), we no longer use a named “sum” variable as temporary storage. Instead, we use the return value of add() anonymously!

As a result, our program is shorter, cleaner, and generally easier to follow (once you understand the concept).

In fact, because cents1 and cents2 are only used in one place, we can anonymize this even further:

Summary

In C++, anonymous variables are primarily used either to pass or return values without having to create lots of temporary variables to do so. However, it is worth noting that anonymous objects are treated as rvalues (not lvalues, which have an address). This means anonymous objects can only be passed or returned by value or const reference. Otherwise, a named variable must be used instead.

It is also worth noting that because anonymous variables have expression scope, they can only be used once. If you need to reference a value in multiple expressions, you should use a named variable instead.

Note: Some compilers, such as Visual Studio, will let you set non-const references to anonymous objects. This is non-standard behavior.

8.x -- Chapter 8 comprehensive quiz
Index
8.13 -- Friend functions and classes

41 comments to 8.14 — Anonymous variables and objects

  • Zafer

    In the last coding example, how were we able to call the Add function directly from the main() function? Why didn’t we use Cents.Add instead? Also, how can we define an anonymous variable like Cents(7) for instance? How does the compiler act in terms of returning pointers or references to be able to define an anonymous variable?

    • In the last example, note that Add() is written as a non-member function. Consequently, it can be called directly. We didn’t use Cents.Add() because we didn’t write an Add() member function for this version of the Cents class. We certainly could have, but it was easier to show anonymous variables in action this way.

      Cents(7) _is_ an anonymous variable because it was never given a variable name. Perhaps I am misunderstanding this part of your question?

      Anonymous variables are always dealt with by value [or const reference]. It is not possible to create a pointer or [non-const] reference to an anonymous variable, nor is it possible to use an anonymous variable where a pointer or [non-const] reference parameter or return value is expected.

      • Josh

        “It is not possible to create a pointer or reference to an anonymous variable.”

        I beg to differ:

        • Alex

          I should have said “non-const references”. Const references to anonymous objects are allowed, non-const references are not (though Visual Studio will let you do so anyway).

  • Chris Buck

    What is a “non-member function” anyway? The line:

    seems pretty confusing to me, as I thought we would have to declare at least the Add() function’s prototype somewhere in the class definition and then use Cents::Add() for the actual implementation?
    Pls excuse me if I missed it and non-member functions had already been covered.

    • A non-member function is a function that does not belong to a class. They are the functions that you first learned about before you even knew what a class was!

      For example:

      This is a simple non-member function. It does not belong to a class. In the same way, the Add() function above is a non-member function, except it adds Cents instead of ints.

      We could certainly have written Add() as a normal member function of Cents (in which case, it would have been Cents::Add()), but it would have been somewhat awkward to do so, since we’d have to call it like this:

      Cents cResult = cCents1.Add(cCents2);

      Probably the best solution would have been to make Add() a static member function of Cents. In that case, we could have called it like this:

      Cents cResult = Cents::Add(cCents1, cCents2);

  • dano

    What’s really throwin me is line #22. Where I understand the:
    Add(cCents1, cCents2) part but the .GetCents is confusing.
    Which .GetCents is being called? cCents1.GetCents() or
    cCents2.GetCents()?
    I’m thinking like: Add(cCents1.GetCents(), cCents2.GetCents())

    Thanks for your help.

    Dano

    • The first thing that happens is that Add(cCents1, cCents2) is called. Add() creates a new Cents object, which it returns to the caller. Then, GetCents() is called on the return value of the Add() function.

  • the joker

    i can’t understand why c1 and c2 are passed by reference ??!!

    • If they weren’t, you couldn’t access them later on in the function:

  • CompuChip

    In fact, I think you could write the main function without any named variables at all:

    • ZNorQ

      REF: Add(Cents(6), Cents(8)).GetCents()
      I also expected this to be true, but it wouldn’t run. I fail to see why this wouldn’t work. :/

    • Bede

      Yes, that works, but you also have to change the Add() and GetCents() functions so that they work with constants (and const refs):

      Just added three times "const".

  • Chip

    Hold your horses. You can write a function of type class? And how this works? :

    Cents cCentsSum = Add(cCents1, cCents2);

    Shouldn’t it be like:

    Cents cCentsSum(Add(cCents1, cCents2));

    I really want to know how things like this work.

    • Gammerz

      declares an object cCentsSum of type Cents and then initialises it, all on one line. It could have been split into two commands:-

      The Add function returns an object of type Cents so this initialisation is valid. Note that the Add function is not a member of the class cents, it’s defined outside the class, so is a “normal” function. It’s ok to use functions or expressions as initialisation values, we are not restricted to literals.

  • mslade

    Great guide. I thought I would add some advice for those new to programming:

    If you’re using the same expression in anonymous values repeatedly, it should probably be a named variable instead. For example, if you’re passing strlen(szName) into the value of 3 different functions, capture it in a named variable and use that three times, instead.

    This way, strlen(szName) doesn’t have to be calculated three times. It also makes the code more compact and thus more readable.

  • Janez

    Function Cents Add() was a bit confusing (as you can see from comments). Especially this part: Cents cCentsSum = Add(cCents1, cCents2);
    Since you’ve never mentioned, that this is one of possible ways to call class constructor (as I recall), this confuses a lot of people. Additionally you used “normal” constructor call in Add function (Cents(c1.GetCents() + c2.GetCents())). Maybe you should mention, that Cents cCentsSum = Add(cCents1, cCents2) is the same as Cents cCentsSum(Add(cCents1, cCents2)), and Add is non-class function with return type Cents. Cheers!

  • Methos

    So I was writing a program to make examples of this chapter of tutorials in one place and ran into a problem and an annoyance. Both of which I think I’ve solved, so this is more story than help request, though if there’s a more elegant way to go about it, I’d be glad to hear that.

    GetValue just prints the string and returns the integer response. DateAndWeather is a class of integer values and get/set functions. main() has previously used GetValue to obtain size, and claimed a new DateAndWeather array of that size.

    My annoyance is that those questions get asked out of order. It occurs to me that since this is the only way that data comes in in my program, I can just flip the order of the questions and my constructor parameters.

    The problem I spent an hour and a half beating my head against my keyboard over is that I included an ID generator in my class, but the IDs were being assigned too high. So for 3 entries, they’d be listed as day 4, 5, and 6. What I ultimately think happened is that the anonymous variable I generated in GetToday went to my constructor, got a new ID, and overwrote the one dPtr[count] got when it was initialized in main. So my new constructor looks like this:

    main() doesn’t send anything and the prototype in the class declaration sets it to false by default, so the increment only occurs when GetToday’s anonymous variable calls it.

    I think. It works now, in any case.

  • Alex why did you wrote the name Cents when returning from Add(). The program works fine without it. Not a very big question but I would like to know if there is a big reason behind that.

    In case you don’t understand my question, i am talking about this:

    • Alex

      Without it, you’re relying on the compiler to implicitly convert an int to a Cents.

      With it, you’re explicitly telling the compiler what kind of object to create and return.

      It’ll work either way in this case. But in general, leaving something up to the compiler is just one more vector for something to unexpectedly go wrong, so being explicit is usually better.

  • Mr D

    Hi Alex,

    The second to last code block example in this lesson has got me really confused!

    I don’t understand the point of the creation of:

    .

    You could have just written it like:

    I believe in this example it's the first time in the tutorial that you've instantiated a class, and then passed another object (2 actually) of the same class to it as the argument. Maybe we need some more explaining about this! If you covered it earlier and i forgot about it, apologies!

    • Alex

      You’re right, I _could_ have written it as you note, however the point of the lesson was to show you a simple example of where an anonymous object could be used instead of a temporary variable.

      It probably would have made more sense to write function Add() as an overloaded version of operator+. I’ll do that when I rewrite the lesson.

      If you replace function Add() with the following:

      I think you’ll agree it’s nice to be able to write:

      Instead of having to use the GetCents() access function to do this:

      > I believe in this example it’s the first time in the tutorial that you’ve instantiated a class, and then passed another object (2 actually) of the same class to it as the argument.

      No such thing happened! 🙂 The function Add() (or the overloaded operator+ in this comment) is not a member function, so I didn’t pass anything to a class I just instantiated.

      Function Add() (or the overloaded operator+ in this comment) simply takes two objects of the same class type, and returns an (anonymous) object of that type back to the caller.

  • Mr D

    Thanks Alex,

    You said:

    [quote]Function Add() (or the overloaded operator+ in this comment) simply takes two objects of the same class type, and returns an (anonymous) object of that type back to the caller.[/quote]

    I sort of get that, but then i don’t understand how this relates to the code in lesson 9.2:

    Here, the two objects are NOT of the same class type, so why place the word Cents before operator+? I really don’t understand what this means (the word "Cents" before operator+)! 🙁

    Or is the answer as simple as: whatever the return type will be, the function type must be the same?

    • Alex

      Yes, the type before the function name is the type that the function will return! So in this case:

      the Cents before operator+ indicates the the function will return a Cents object (which it does using the return statement)

      This doesn’t have anything to do with the function parameters, which could be of any defined type (e.g. you could write an operator+ that took an int and a double and returned a Cents if you wanted -- though it would be kind of silly).

  • Mr D

    Thanks Alex, i’m slowly but slowly getting my head around it!

  • RS

    Alex, thank you so very much for this tutorial! After years of fearing pointers, and OOP, suffering from one bad teacher and another, I am able to feel good about these topics.
    Any chance we might see a comprehensive quiz for this and the next couple of chapters soon?

    My goal is to get the whole tutorial done by the end of the holidays, and move on to other challenges that may help me find a job. Phew!

    • Alex

      Probably not soon. 🙁 I’m adding comprehensive quizzes as I rewrite the lessons (because those lessons add new material, and I want the quizzes to reflect that new material as well as the existing stuff). Chapter 8 is going to take a while to get through, due to the holidays and the sheer amount of material covered in this chapter.

  • RS

    I hope you get to them sometime. 🙂 I really appreciate your lessons. In the meanwhile, I’ll probably get my partner to assign me quizzes, and keep checking back to any new quizzes that might magically appear 😉

  • Diksha

    I have a little doubt. Suppose I have a class test.
    Suppose  I initialise the object the following way:
    test obj  = test(3); //test(int) is a constructor
    Will an anonymous object be created in this case? Will test(3) create an anonymous variable and then do assignment to assign the value of data members to obj?

    • Alex

      The answer is “it depends”. In some compilers, this will create an anonymous variable and initialize the object using the copy constructor for the class. However, because this is inefficient and for no good reason, many compilers “elide” (omit) the creation of the temporary object and just initialize the object directly.

  • Ali

    Hi Alex and thanks a million for your GREAT C++-teaching site!

    I wonder in the following code:

    class Test
    {
    public:
       void print(){std::cout << "Hi there!" << std::endl;}
    }

    int main()
    {
      Test::print();
      return 0;
    }

    why can’t we use:   Test.print()
    instead of          Test::print() ?

    thanks in advance!
    love!
    Ali

    • Alex

      Not sure what you mean. Since function print isn’t static, Test::print() won’t work, and you can never call Test.print() since Test is the name of the class, not an instance of the class.

      • Ali

        Oh! Sorry!
        You are right!
        I meant this:

        class Test
        {
        public:
           static void print(){std::cout << "Hi there!" << std::endl;}
        }

        int main()
        {
          Test::print();
          return 0;
        }

        why can’t we use:   Test.print()
        instead of          Test::print()
        as an anonymous object?

        Thanks again!

        • Alex

          operator. is for selection of members of instantiated objects.
          operator:: is for selection of identifiers within a given scope.

          Operator. isn’t appropriate in this case since we don’t have an instantiated object of type Test. So in this case, we must use :: to select static function print within the scope of class Test.

  • Arash

    Hi Alex,

    You are great !

    we can remove const keyword above and still it works which shouldn’t :

    I mean we pass lvalue to function and we should get error. Right?
    Thanks.

    • Alex

      Yes, you should get an error, because you can’t pass a temporary rvalue to a reference (anonymous objects are treated as rvalues). However, it looks like Visual Studio lets you do this anyway -- so this appears to be an issue with the compiler being permissive. It may be implicitly converting the reference to an r-value reference (something that was added in C++11 that I don’t have lessons for yet -- it’s on my todo list).

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter