Leon
Leon

Reputation: 32484

Can the use of C++11's 'auto' deteriorate performance or even break the code?

This question is the opposite of an existing question "Can the use of C++11's 'auto' improve performance?"

One of the answers to that question indicated that usage of auto can have not only positive but also negative effects.

I believe we need a separate question, with answers focusing on that side of auto.

Upvotes: 4

Views: 615

Answers (3)

Seshadri R
Seshadri R

Reputation: 1212

Blind search-and-replace of all type declarations by auto can be a head-ache, whenever braced initialization is used:

class Point
{
public:
    Point (int x1, int y1) { x = x1; y = y1; }
private:
    int x, y;
};      

int main() 
{
    Point p{5, 6};
    auto q{5, 6}; // Error. Uniform initialization is not REALLY uniform
}

The first declaration of variable p is correctly deduced as a call to the constructor accepting two integers. But the auto variable q searches for a constructor requiring std::initializer_list<int> and hence fails to compile.

Upvotes: 0

kfsone
kfsone

Reputation: 24259

Your question title specifies 'performance'.

auto is a compile time construct that allows itself to be substituted with a deduced type. Its use doesn't result in different machine instructions, than if you have hand-written the typename it deduced.

The problem is that, in managing performance, type specification and casting is often crucial, and auto can hide that leading programmers to say something different than they intended:

std::vector<std::array<BigStruct, 10000>>& f();
auto va = f();  // copy
for (auto v: va) {  // copies
    // ...
}

if the programmer had written:

std::vector<std::array<BigStruct, 10000>> va = f();

or

for (std::array<BigStruct, 10000> v : va)

they would have recognized they were specifying by-value. But std::array<BigStruct, 10000> is what auto deduces here and in these cases that translates to by-value.

People drop their guard and forget that auto deduces the type, it doesn't include the ref qualification.

auto& va = f();  // reference
for (auto& v : va) {  // references

There was a performance affect here, but it wasn't caused by auto it was a side-effect of (accidentally) explicitly specifying a copy.

auto doesn't mean the same as this it means an instance of this.

auto va = f();   // an instance-of what f returns, thus a copy.
auto& va = f();  // a reference to an instance-of, thus by reference.

Upvotes: 2

Leon
Leon

Reputation: 32484

With auto there is no conversion at the variable declaration+initialization line. But if such conversion must happen anyway, it better happen once during initialization than multiple times later.

struct X {
    ...
};

struct Y {
    operator X() const;
    ...
};

Y foo(); // maybe, originally its return type was X but later was changed to Y
void bar(const X& );

const auto x = foo();           // <-- conversion not happening here
                                //
for ( int i = 0; i < 100; ++i ) //
    bar(x);                     // <-- silently rages here

Such a deferred conversion may break the code when auto is combined with lazy evaluation (real world example 1, example 2):

class Matrix { ... };

class MatrixExpression {
    ...
    operator Matrix() const;
};

MatrixExpression operator+(const Matrix& a, const Matrix& b);
std::ostream& operator(std::ostream& out, const Matrix& m);

Matrix a = ...;
Matrix b = ...;
auto c = a + b; // evaluation of the matrix addition doesn't happen here
a[0][0] += 1;
std::cout << c; // matrix addition is evaluated here, using the new state of 'a'

Upvotes: 5

Related Questions