19

I have a piece of code like this:

class Data
{
    public:
        Data(const std::vector<int> &_data)
        {
            my_data = _data;
        }

    private:
        std::vector<int> my_data;
};


int main()
{
    std::vector<std::shared_ptr<Data>> vec = {
        std::shared_ptr<Data>(new Data(std::vector<int>({ 1, 2 ,3 }))),
        std::shared_ptr<Data>(new Data(std::vector<int>({ 3, 4 ,5 })))
    };

    // breakpoint

    return 0;
}

somehow when I pause the program to check values (at breakpoint), the first (vec[0]) element is destroyed while the second one (vec[1]) is fine. What is going on here? Is that a bug in compiler? I am using new Visual Studio 2013.

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Qwrk
  • 330
  • 2
  • 7
  • 1
    Did you drop a debug-out in a `Data::~Data()` destructor to confirm that? And are you possibly compiling with debug symbols on a release-build? – WhozCraig Nov 02 '13 at 23:28
  • Yes, I added the `Data::~Data()` in order to check if object is getting destroyed and in both cases, Debug and Release, that is exactly what happened. – Qwrk Nov 02 '13 at 23:36
  • I'm seeing the same thing with the above code and the above setup. Both debug and release builds show the same behavior. Here's the output when I add trace `cout`s to the code: *1* **`Data::Data()`**, then *2* **`Data::Data()`**, then *3* **`Data::~Data()`**, then *4* **`BREAKPOINT`**, and finally *5* **`Data::~Data()`**. – yzt Nov 03 '13 at 00:33
  • how odd. I have to try this with vs2012 now. – WhozCraig Nov 03 '13 at 01:02
  • @WhozCraig The initialization list syntax is not available in VC11, right? And I just checked it, even in VC12, when you use two `emplace_back` calls instead of constructing with the (outer) initialization list, the code behaves *correctly*. – yzt Nov 03 '13 at 01:06
  • 1
    I just tried using `std::make_shared` and it didn't help (the apparently erroneous behavior persists.) – yzt Nov 03 '13 at 01:19
  • @Qwrk In the `Data` constructor, if you change the signature to pass the parameter *by value* instead of by reference, the problem *disappears*. Note that passing by `const &` doesn't help. Also, if you change the internal member type of `Data` class to a simple `int`, instead of a `vector`, the problem *goes away* (irrespective of how you pass it to the constructor.) – yzt Nov 03 '13 at 01:41
  • 1
    Then it's possibly a bug. Huge bug. – Siyuan Ren Nov 03 '13 at 03:25
  • 4
    I reported this bug here: [link](https://connect.microsoft.com/VisualStudio/feedback/details/807610/first-element-of-vector-is-destroyed-initializing-from-initializer-list) – Qwrk Nov 03 '13 at 12:30
  • BTW, This code doesn't compile in VS2012. – egur Nov 20 '13 at 21:59
  • I just tried VS2013 Update 1 and although the link to the bug reported above is listed as fixed the same problem occurs. – Mark Tolonen Jan 25 '14 at 22:45
  • FYI, this code finally works correctly with VS2013 Update 3. – Mark Tolonen Aug 26 '14 at 20:33

4 Answers4

5

What happens is that a bug in VS2013 causes a double delete on the first item of the initializer_list. Here's the flow:

  1. initializer_list is constructed.
  2. target vector is reserved a size of 1 and first item is copied (via copy constructor).
  3. vector grows slowly to initializer_list size.
  4. initializer_list is destroyed via a vector-destructor (i.e. delete[]). Last element is destroyed first.
  5. First element is destroyed again via scalar-destructor (i.e. delete).

I've seen this on another post and verified the behavior using a debugger. See here

For VS2013, initializer_list is good for basic types only.

Community
  • 1
  • 1
egur
  • 7,830
  • 2
  • 27
  • 47
0

I guess it is something with the shared pointer note that a shared pointer object will be destroyed if the last remaining shared_ptr owning the object is destroyed. the last remaining shared_ptr owning the object is assigned another pointer via operator= or reset(). I hope this helps

Ibrahim
  • 342
  • 4
  • 14
0

I didn't have VS2013, so I check the code in MinGW 4.7 in windows, I didn't found the problem above-mentioned. When I stop at that breakpoint, both the first (vec[0]) element and the second (vec[0]) element all is not destroyed.

So I guess that this problem's reason is that you write some simple code at that breakpoint, vs's complier optimize it, so you stopped at a strange place exactly between two elements' destructor function.

You can post out the disassembly code above that we can identify the problem explicitly. :)

  • 1
    I know it's not the problem in other compilers, that's why I reported this as a bug. Here is [disassembly code](http://ideone.com/MRlKjU) for main function, I think the 154 line is what causes this bug. :) And it doesn't matter if I put some extra code after declaration or not, it looks like it's getting destroyed right after initialization. – Qwrk Nov 20 '13 at 18:24
0

This is probably a bug in compiler. If you add some logging to Data constructor and destructor then you will see that is going on.

std::cout << __FUNCTION << ":" << this << std::endl;

I confirm the issue in Visual Studio 2013. Under 'clang' this code behaves as expected.

esmirnov
  • 376
  • 2
  • 13