Temporary objects: lifetime and Extensions – part 2


This post is centered on “stack-use-after-scope” which is an issue we see often in code review and code sanitizer / valgrind reports. Here’s an example:

struct SimpleCalc{
    SimpleCalc( const std::vector<int>& my_vec ) : 
        m_vec (my_vec) {};

    int calculate() {
        // Uses the m_vec and its content.
    };
private:
    const std::vector<int>& m_vec;
};

// < some code >

// Solution #1
SimpleCalc my_calc( std::vector<int>{ /*some values*/ } ); // <- Problem here. 
// The temp created in the argument will have it's 
// lifetime end with this full expression.
my_calc.calculate(); // Stack-use-after-scope.


The first/simplest solution (let’s call it solution 1) that usually comes to mind is to create an lvalue and pass it to the constructor, as such:

Continue reading “Temporary objects: lifetime and Extensions – part 2”

Same same: Covariant return types.

In this post, I want to talk about a specific feature. To set the table, it has to do with the return type of virtual functions. The compiler usually enforces that the return type of an override method match exactly the type of the base method declaration. However, there is a little leeway, with covariant return types. This is an interesting feature in C++ which isn’t supported in C#. In a nutshell, it allows the overriding method to change the return type, as long as it is a covariant return type. For example:

class Y {};
class Z : public Y {};

struct A {
   virtual Y* foo() { return new Y(); }
};
struct B : public A {
   Z* foo() { return new Z(); } // legal code. Notice the 
                                // change of return type. 
};

This follows the Liskov Substitution Principle (LSP) very nicely, since class Z IS A class A and can be substituted as such. The standard explains this in section [class.virtual / 10.3 ] paragraph 7. This is where the conditions placed on using covariant return types are outlined:

Continue readingSame same: Covariant return types.

Short circuits and the evaluation order of function parameters

This post isn’t about our favorite old school robot Johnny 5. So let’s start with the second part: the non defined order of evaluation of function parameters (yes, it’s non defined)

if(A(C()), B())

The compiler is free to evaluate A(), then B(), C(), or B(), then C(), then A(), etc. This could be troublesome if you expect a variable to be initialized in A() to be used in B(). The one guarantee is that C() is evaluated before A().

Another item which has some fun with the order of evaluations are the logical operators. Probably a bit of an “yeah, makes sense”, but worth the refresher.

operator || and operator && won’t necessarily evaluate all their arguments. This is known as “Short circuit evaluation”. For example:
Continue readingShort circuits and the evaluation order of function parameters