Search

8.14 — Anonymous objects

In certain 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 object. An anonymous object is essentially a value that has no name. Because they have no name, there’s no way to refer to them beyond the point where they are created. Consequently, they have “expression scope”, meaning they are created, evaluated, and destroyed all within a single expression.

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

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

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 object. A copy of this anonymous object is then passed to the printValue() function, (which prints the value 8) and then is destroyed.

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 objects:

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 objects are primarily used either to pass or return values without having to create lots of temporary variables to do so. Memory allocated dynamically is also done so anonymously (which is why its address must be assigned to a pointer, otherwise we’d have no way to refer to it

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 objects 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.15 -- Nested types in classes
Index
8.13 -- Friend functions and classes

56 comments to 8.14 — Anonymous objects

  • Livio

    Hello Alex,
    I saw your answer to

    hitman
    January 6, 2017 at 5:32 am · Reply    

    Can you please add some more details? I am wondering how I could arrive to this code from what I learned in the previous lessons…
    What is the reasoning behind that?

    Thanks

    • Alex

      This is using a member initialization list (covered in the chapter on arrays) to initialize an array with student objects. The student object initializers are anonymous (covered in this lesson).

  • lakon

    I paused long time too to understand this example. Especially the type "Cents" and return below:

    It will be much easier to digest if "int" is used:

    and subsequently

    .

    When is user defined type (as in Cents above) is compulsory?
    I check result is the same, would that be any potential issues by using int?

    • Alex

      In this case, because the Cents class only contains an int, you could do what you suggest -- but in general, if you add two objects, you’d expect to get an object of the same type back. I’d argue that even in this case, it’s still better to return a Cents, so that the user can call other functions or cast to an int if they desire -- if you return an int, then the user is forced to use an int, which potentially limits what they can do after they add two Cents together.

  • Furqan Amin

    Are these anonymous objects same as the anonymous objects created by derived classes of their base classes in order to hold the data members stored in the base classes?

  • apfelpektin

    i have some questions about object lifetime and ‘expression scope’:

    since function add() returns by value..

    1) is a copy made of the temporary anonymous object and returned to be used in the calling expression after the object inside the function has already been destroyed?

    2) returning as const reference ‘const Cents&’ would be wrong (and also gives me a warning here) because the returned reference is invalid after the function finished, right?

    3) passing the temporary anonymous objects to the function by const reference is ok because the ‘expression scope’ is guaranteed to end AFTER the function finished, right? or is there even some reference counting going on?
    i read here: http://stackoverflow.com/a/1152218
    quote: "A temporary bound to a reference parameter in a function call (5.2.2) persists until the completion of the full expression containing the call"

    ..so completion of the expression includes completion of the call, right?

    i also got confused because the quote in the link says something that sounds like reference counting to me:

    quote: "The temporary to which the reference is bound […] persists for the lifetime of the reference except as specified below."
    i don’t know what ‘below’ means there either, but wouldn’t returning a const reference also work then?

    awesome tutorial btw!

    [ps: editing the message breaks the code tags]

    • Alex

      1) Correct.
      2) Correct.
      3) Correct. The return value (by value) has expression scope, which means it lasts until the end of the function call. If you assign the return value to a const reference, the const reference modifies the lifetime of the return value so that instead of dying at the end of the expression, it dies whenever the const reference to it does.

      • apfelpektin

        yes, that lifetime prolonging still isn’t completely clear to me. i better just stick to the general rules for now.
        thank you for you time 🙂 much appreciated.

  • Jon Spencer

    I am curious why you use the phrase "anonymous variable". It seems to me, based upon the C++ standard, to be an oxymoron.  A C++ variable is a named object, and thus the translation of "anonymous variable" is "anonymous named object," or an unnamed named object.  I believe that if you used instead the phrase unnamed object, your otherwise excellent explanation would be much more clear, and easier for the beginner to understand.

  • hitman

    Hey Alex PLEASE HELP ASAP,

    class student
    {
    public:
    int roll;
    student(int x,int y)
    {
    roll=x+y;
    }
    };
    main()
    {

    //Creating array of objects
    student obj[2] {(2,3),(4,5)};
    //but somethingis wrong this line,please help

    cout<<obj[0].roll;
    cout<<obj[1].roll;

    }

    • Alex

      The compiler doesn’t know how to convert (2,3) and (4,5) into members of the array. You need to do this instead:

      • hitman

        Okay Thanks,
        Just one more thing  from <JAVA>
        Case1:

        class D
        {
        public static D[] arr={new D(4,5),new D(3,5)};
            public D(int x,int y)
            {
                
            }
        }

        Case 2:
        class D
        {
        public static D[] arr=new arr[2];
        arr[0]=new D(2,3);
        arr[1]=new D(4,5);
        D()
        {
        }
        }

        Case 1 works fine but in case 2 it is asking the array of objects to be declared in a method,which i don’t want to.
        Please tell me the difference these 2 cases.

        • Alex

          Neither of these should work.
          Case 1 shouldn’t work because you’re trying to initialize a static member inside the class definition with a non-enum/non-int value.
          Case 2 doesn’t work because you have two assignment statements that live directly in the class definition, outside of any functions -- when would you expect these to get executed?
          And both cases additionally won’t work because you’ve declared an array of type D, but you’re trying to initialize the array elements with pointers (which have type D*).

          The best thing to do here (in both cases) would to move the initialization outside the class. Then, for the second case, have the initialization call an init function, like this:

  • 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).

  • 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.

  • 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.

  • 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 😉

  • 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.

  • Mr D

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

  • 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

    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.

  • 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.

  • 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.

  • 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!

  • 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.

  • 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.

  • 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".

  • 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:

  • 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.

  • 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);

  • 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).

Leave a Comment

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