Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
135 views
in Technique[技术] by (71.8m points)

c++ - Difference observed between MSVC14.1 and gcc8.3 when a destructor call for an automatic variable amends a function return value

Consider the following (to be compiled with C++14)

#include <iostream>
#include <vector>

// Foo adds an element to a std::vector passed by reference
// on construction in the destructor
struct Foo {
    Foo(std::vector<double>& v) : m_v(v){
    }
    ~Foo(){
        m_v.push_back(1.0);
    }
    std::vector<double>& m_v;
};

std::vector<double> bar(){
    std::vector<double> ret;
    Foo foo(ret);
    return ret;
}

int main(){
    std::cout << bar().size() << "
";
}

In gcc8.3 the output is 1, which means that foos destructor has an effect on the returned vector.

In MSVC14.1 the output is 0. You can force the output to be the same as gcc8.3 by replacing the line Foo foo(ret); with {Foo foo(ret);} (i.e. by forcing the scope).

I don't think this is dangling reference undefined behaviour (because ret is declared before foo) but rather that this could be a bug in MSVC14.1 (and I will create a bug report if so). Does anyone know for sure?

See https://ideone.com/pnxWuJ

question from:https://stackoverflow.com/questions/64977541/difference-observed-between-msvc14-1-and-gcc8-3-when-a-destructor-call-for-an-au

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I think the relevant part of the C++20 standard is [stmt.return], which says

The copy-initialization of the result of the call is sequenced before the destruction of temporaries at the end of the full-expression established by the operand of the return statement, which, in turn, is sequenced before the destruction of local variables (8.7) of the block enclosing the return statement

So the result of the function call (the return value) should be constructed first, then foo is destroyed. Since the returned value is constructed before foo's destructor is run, the result should be 0.

The [class.copy.elision] section says

When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the constructor selected for the copy/move operation and/or the destructor for the object have side effects.

So both compilers can be considered correct.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...