1

This program works as expected:

#include <iostream>
#include <string>
#include <vector>    
using namespace std;

struct Thumbnail
{
    string  tag;
    string  fileName;
};

int main()
{
    {
        Thumbnail newThumbnail;
        newThumbnail.tag = "Test_tag";
        newThumbnail.fileName = "Test_filename.jpg";

        std::vector<Thumbnail> thumbnails;

        for(int i = 0; i < 10; ++i) {
            thumbnails.push_back(newThumbnail);
        }
    }
    return 0;
}

If I copy and paste the main block of code in another project (still single threaded), inside any function, I get this exception from the line commented // <-- crash at the 2nd loop:

terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc

If I clear the vector before any push_back, everything is all right (but of course this is not the desired behaviour); this makes me think that it is like if the vector could not store more than one such object.

This is the function where the code is crashing:

int ImageThumbnails::Load(const std::string &_path)
{
    QDir thumbDir(_path.c_str());

    if(!thumbDir.exists())
        return errMissingThumbPath;

    // Set a filter
    thumbDir.setFilter(QDir::Files);
    thumbDir.setNameFilters(QStringList() << "*.jpg" << "*.jpeg" << "*.png");
    thumbDir.setSorting(QDir::Name);

    // Delete previous thumbnails
    thumbnails.clear();

    Thumbnail newThumbnail;

    ///+TEST+++
    {
        Thumbnail newThumbnail;
        newThumbnail.tag = "Test_tag";
        newThumbnail.fileName = "Test_filename.jpg";

        std::vector<Thumbnail> thumbnails;

        for(int i = 0; i < 10; ++i)
        {
            TRACE << i << ": " << sizeof(newThumbnail) << "  /  " << newThumbnail.tag.size() << " / " << newThumbnail.fileName.size() << std::endl;
            //thumbnails.clear();                   // Ok with this decommented
            thumbnails.push_back(newThumbnail);     // <-- crash at the 2nd loop
        }

        exit(0);
    }
    ///+TEST+END+++
...

This is the output:

> TRACE: ImageThumbnails.cpp:134:Load  
0: 8  /  8 / 17
> TRACE: ImageThumbnails.cpp:134:Load  
1: 8  /  8 / 17
terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc

Why do I get this different behaviour for the same piece of code in two different projects?

Platform: Windows 7, MinGW 4.4, GCC

Pietro
  • 12,086
  • 26
  • 100
  • 193

2 Answers2

2

To add to this (because first Google result): In my szenario i got bad_alloc even when i still had a few GBs of RAM available.

If your application needs more than 2GB of memory you have to enable the /LARGEADDRESSAWARE option in the Linker settings.

If you need more than 4GB you have to set your build target to x64 (in Project Settings and the Build configuration)

Due to how the automatic resizing of vectors works you will hit the breakpoints at ~1gb / ~2gb vector size

Paul
  • 5,524
  • 1
  • 22
  • 39
1

If it is crashing when using the exact same code in another application, there is the possibility that the program is out of memory (std::bad_alloc exceptions can be because of this). Check how much memory your other application is using.

Another thing ... use the reserve() method when using std::vectors and you know ahead of time how many elements are going to be pushed into the vector. It looks like you are pushing the exact same element 10 times. Why not use the resize() method that includes the default object parameter?

Andrew
  • 1,581
  • 3
  • 18
  • 31
  • I push the same element just for testing. – Pietro Oct 17 '13 at 14:28
  • Using reserve() it does not crash any more. This is even stranger! – Pietro Oct 17 '13 at 14:34
  • Could it mean that reserve() and push_back() use different methods to request memory from the system, and only the first one succeeds? – Pietro Oct 17 '13 at 14:36
  • What happens if you push more elements than you reserved? Say you reserve 100 elements and then push 101 elements. What happens then? – Andrew Oct 17 '13 at 14:42
  • A new larger chunk of memory will be reserved, the whole previous memory block will be copied, and the new element will be added. – Pietro Oct 17 '13 at 14:46
  • 1
    So, excluding performance, from an observer point of view, it should make no difference to just push_back an element or reserving space for it and then push it back. – Pietro Oct 17 '13 at 14:51
  • Correct. Memory allocations are very expensive operations and that is why methods like reserve() exist. But from a functional standpoint, no it shouldn't be any different. Do you have a core dump for the crash? What exact spot in the code is it crashing in? – Andrew Oct 17 '13 at 14:58
  • It crashes at the line commented with: `// <-- crash at the 2nd loop` – Pietro Oct 17 '13 at 15:01
  • Consider I am dealing with two short strings only... (less than 20 characters long) – Pietro Oct 17 '13 at 15:03
  • I know that, but what does the core dump say? What does the stack trace look like? – Andrew Oct 17 '13 at 15:13
  • How are you debugging the program? Are you using Visual Studio? Attach to the program using your debugger and let the crash happen again. The debugger should provide some information. – Andrew Oct 17 '13 at 15:43
  • I am using QtCreator with MinGW. – Pietro Oct 17 '13 at 15:45
  • I am accepting your answer because, even if it does not provide a straight solution to my question, it shows a workaround (reserve) that is good in my case. – Pietro Oct 17 '13 at 17:00