initializer_list handling broken, destructors of temporary objects called twice - by Debugini

Status : 

 


4
0
Sign in
to vote
ID 791137 Comments
Status Active Workarounds
Type Bug Repros 4
Opened 6/27/2013 12:54:39 AM
Access Restriction Public

Description

initializer_list handling seems to be broken.
Destructors of temporary objects are called twice. The first destructor call happens _before_ copying the temporary object, thus the objects received by the vector are in an incorrect state on Visual Studio 2013 Preview. 
Visual Studio 2013 RC behaves better but still not correct.
Sign in to post a comment.
Posted by Niels Dekker on 6/10/2014 at 6:51 AM
Thanks! I saw at http://blogs.msdn.com/b/vcblog/archive/2014/06/09/bugs-fixed-in-the-spring-update.aspx that the bug has been fixed. And indeed... I tried the code example from the Details section, using VS2013 Update 2, and the bug appears to be gone away... :-) My output:

C:\Users\Bar>cl /EHsc C:\Users\Bar\foo.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 18.00.30501 for x86
Copyright (C) Microsoft Corporation. All rights reserved.

foo.cpp
Microsoft (R) Incremental Linker Version 12.00.30501.0
Copyright (C) Microsoft Corporation. All rights reserved.

/out:foo.exe
foo.obj

C:\Users\Bar>foo
construct at 0020FA14
construct at 0020FA30
construct at 0020FA4C
copy construct from 0020FA14 at 002B6C80
copy construct from 0020FA30 at 002B6C9C
copy construct from 0020FA4C at 002B6CB8
destruct at 0020FA4C
destruct at 0020FA30
destruct at 0020FA14
Np at 002B6C80 [A]1
Np at 002B6C9C [B]2
Np at 002B6CB8 [C]3
1 foo
2 bar
3 baz
Posted by ichramm on 1/31/2014 at 7:53 PM
Still happening after installing the Update 1 for Visual Studio 2013.

But it happens only with nested initializer list.

The following is a minimal example about how to reproduce the issue.

A more complete example can be found in the attached file nested_initializer_list.cpp

#include <map>
#include <string>
#include <vector>
using namespace std;
class test
{
public:
    string _name;
    map<string, test> _childs;
    test(const char *name)
        : _name(name) { }
    test(const string& name)
        : _name(name) { }
    test(initializer_list<std::pair<const string, test>> childs)
        : _name("composite" + to_string(++compositesCount))
    {
        _childs.insert(childs);
    }
    test(const test& o)
        : _name(o._name), _childs(o._childs) { }
    test(test&& o)
        : _name(move(o._name)), _childs(move(o._childs)) { }
    ~test() { }
};

int main() {
    test t{
        { "one", "is 1" },
        { "two", "is 2" },
        { "three", {
            { "threeDotOne", "is 3.1" },
            { "threeDotTwo", "is 3.2" }
        }},
        { "four", "is 4" },
        { "five", "is 5" },
    };
}
Posted by Xiang [MSFT] on 11/25/2013 at 2:37 PM
Hi:
    Thanks for reporting the issue.
    A fix for this issue has been checked into the compiler sources. The fix should show up in the future release of Visual C++.

Xiang Fan
Visual C++ Team
Posted by Debugini on 9/11/2013 at 4:22 AM
The problem is only partially fixed in VS 2013 RC.

Now the output of the test program is better than before, but 003EFE40 is destructed twice.

construct at 003EFE40
construct at 003EFE5C
construct at 003EFE78
copy construct from 003EFE40 at 00840100
copy construct from 003EFE5C at 0084011C
copy construct from 003EFE78 at 00840138
destruct at 003EFE78
destruct at 003EFE5C
destruct at 003EFE40
destruct at 003EFE40
Np at 00840100 [A]1
Np at 0084011C [B]2
Np at 00840138 [C]3
1 foo
2 bar
3 baz

Posted by Macy [MSFT] on 6/27/2013 at 2:20 AM
Thanks for your feedback.

We are rerouting this issue to the appropriate group within the Visual Studio Product Team for triage and resolution. These specialized experts will follow-up with your issue.
Posted by Macy [MSFT] on 6/27/2013 at 1:50 AM
Thank you for your feedback, we are currently reviewing the issue you have submitted. If this issue is urgent, please contact support directly(http://support.microsoft.com)