0

I have a class where I define a circular buffer like so:

class cTest
{
    public:
    boost::circular_buffer<std::vector<std::pair<double, double>>> circDat;
       cTest() : circDat(1000)
       {
       }
};

I then create a stl vector of type cTest

std::vector<cTest> vC;

Afterwards I try to fill the vector like this:

for (unsigned int i = 0; i < 4; ++i)
{
    cTest obj;
    vC.push_back(obj);
}

While this works in Debug mode, in Release, it crashes (sometimes, when I run with from Visual Studio, I get a Heap Corruption message). The boost documentation mentions, that in Debug mode, the uninitialized memory is filled with '0xcc'. I assume, the error I get, has its root in uninitialized memory. But I am not really sure, how to fix this problem.

If I use pointers, it seems to work:

std::vector<cTest*> vC;
for (unsigned int i = 0; i < 4; ++i)
{       
    cTest* obj = new cTest;
    vC.push_back(obj);
}

But I still do not know, what the problem with the first version is. If anyone does know, I'd appreciate the help.

Edit:

I've tried to create a minimal, reproducable code but failed. It also seemed to crash randomly, not really correlating to the lines added/removed. I then stumbled on the /GL flag in Visual Studio 2015.

After turning the /GL flag off (in the GUI project - in the library project it can stay on), I've been unable to recreate the crash. I do not know, if this is really a fix. But it seems like there was a similar problem present in Visual Studio 2010: crash-in-program-using-openmp-x64-only

Edit2:

I've managed to pull together a minimal working example. The code can be downloaded here:

https://github.com/davidmarianovak/crashtest

You need Boost (I used 1.60) and QT5 (I used 5.6.3). Build GoAcquire in Release (/GL is active in Visual Studio). Afterwards, build GoGUI in Release (activate /GL and use 'standard' for link-time code generation). After you've built it, run it and it should crash.

The crash can be avoided by changing this in 'GoInterface.hpp' line 22:

void fillGraphicsViews(std::vector<cSensorConstruct> vSens);

to

void fillGraphicsViews(std::vector<cSensorConstruct> &vSens);

But I do not really believe that it is the problem. Can anyone tell me, what I'm doing wrong? I'm using Visual Studio 2015 for this.

Lgum
  • 31
  • 6
  • Please post a [mcve]. – wally Dec 11 '17 at 13:18
  • 1
    I bet you're forgetting about iterator/reference invalidation. So the problem is ***not*** with the code shown – sehe Dec 11 '17 at 13:20
  • I cannot post a working example from the code because it's burried within a library that is called by a gui. However, the code I posted is directly called in the constructor of the class - so there is not much going on before that. Creating the code on it's own like this https://pastebin.com/6ccPjuzZ works without a crash. – Lgum Dec 11 '17 at 13:58

1 Answers1

1

I bet you're forgetting about iterator/reference invalidation. So the problem is not with the code shown.

This makes sense since you report that pointers seem to work: the pointers stay the same even if push_back causes reallocation.

Simply don't hold on to references/iterators to vector elements when you don't know that they're going to stay valid.

If your vector has a known maximum size, you could "cheat" by reserving the capacity ahead of time:

static constexpr size_t MAX_BUFFERS = 100;

std::vector<cTest> vC;
vC.reserver(MAX_BUFFERS); // never more

And then perhaps guard the invariant:

assert(vC.size() < MAX_BUFFERS);
vC.push_back(obj);
sehe
  • 374,641
  • 47
  • 450
  • 633
  • I do know the capacity beforehand - however, reserving it, does not change the crash behaviour. Using a 'debugging' help, by printing out infos after each 'action' reveals, that the first loop seems to work - but once the second loop starts, it crashes. I.e. qDebug() << "Creating new object\n"; etc. prints all the lines out for the first loop. The second loop then crashes. Can it be that the object goes somehow out of scope? – Lgum Dec 11 '17 at 14:20
  • Come on. There is no second loop. We're not psychics. Of you want help, improve the question. Yes lifetime issues are almost certainly the culprit. I don't see enough reason to narrow my diagnosis down until we see a self contained example. – sehe Dec 11 '17 at 15:13
  • I meant second iteration of the loop. Sorry for the wrong use of nomenclature. I am unable to provide a working sample, because on its own, it works. Inside the GUI it fails. After changing the qt ui object to a pointer, it also stops crashing. As of such I assume that there's something else badly broken. Thank you for your comments. – Lgum Dec 11 '17 at 16:29
  • Same difference. There is no second invocation of the loop. Next time edit your question (I didn't see your comment with the pastebin. Here's a live demo of that: http://coliru.stacked-crooked.com/a/bb3e66e878eb3a8c) – sehe Dec 11 '17 at 16:33
  • Out of curiosity: What's the nomenclature when a loop increments by 'one'? In my example, when 'i' increases from '0' to '1'? – Lgum Dec 12 '17 at 14:24