Crash in debug, works in release?

Started by
6 comments, last by Iced_Eagle 15 years, 2 months ago
Recently I tried to learn templates and I wanted to put them to use writing a very simple memory manager (wrappers on new and delete, actually). I met a strange behaviour of STL string I cannot explain logically. Consider these two pieces of code:

#include <iostream>
#include <string>

class MemoryManager
{
  public:
    MemoryManager(){}
    ~MemoryManager(){}
    template <class allocType> void allocate(allocType* _data, unsigned int _size, std::string _source)
    {
        _data = new allocType[_size];
    };
};

MemoryManager memman;

int main()
{
  float* i;
  memman.allocate<float>(i,1,"test");
  *i = 5;   // crash here
  std::cout << *i;
  return 0;
};

and a second one, with different function arguments

#include <iostream>
#include <string>

class MemoryManager
{
  public:
    MemoryManager(){}
    ~MemoryManager(){}
    template <class allocType> void allocate(allocType* _data, unsigned int _size)
    {
        _data = new allocType[_size];
    };
};

MemoryManager memman;

int main()
{
  float* i;
  memman.allocate<float>(i,1);
  *i = 5;
  std::cout << *i;
  return 0;
};

Now, the second code works flawlessly. On the other hand, the first one crashes in debug mode and works fine in release. Does anyone have an idea what's going on? I don't even USE the passed string, it must be STL doing something to me :( By the way, I am using Code::Blocks and MinGW.
OpenGL fanboy.
Advertisement
I think you should try this test:
int main(){  float* i;  std::cout << "initial value of i " << i << '\n';  memman.allocate<float>(i,1);  std::cout << "allocated value of i " << i << '\n';};

... allocate(allocType* & _data ...
i is a pointer. You don't initialize it, so it holds nothing. When you send him to the function allocate, a new pointer name _data is created. Any changes made to the pointer _data will not affect the pointer i. Changes to the data referred by the pointer _data will affect the data referred by the pointer i, since they refer to the same data - as long as you don't change the pointer _data before you change the data it refers.

That means that if you allocate some memory and put a reference to it in the pointer _data, the pointer i will not change. It will still point to the same place in memory it pointed before. Therefore, calling the function allocate has no effect('cept leaking memory, ofcourse).


Change the function's title to this:
template <class allocType> void allocate(allocType* &_data, unsigned int _size, std::string _source)

Notice the '&'? That will send the pointer by reference, and any changes to the pointer _data will affect the pointer i.
-----------------------------------------Everyboddy need someboddy!
That fixed it.
Still, I don't understand why it works in release mode without the &.
I tried this:

std::cout << "value before: " << *i << "\n";memman.allocate<float>(i,1,"test");*i = 1673;std::cout << "value after: " << *i << "\n";


and it gives me:

Quote:
value before: 5.95133e-039
value after: 1673


if the data isn't allocated, I shouldn't be able to change it? Does that mean that I'm changing an undefined location in memory and it's just the release build mode that doesn't check access violations?
OpenGL fanboy.
Quote:Original post by i_luv_cplusplus
if the data isn't allocated, I shouldn't be able to change it? Does that mean that I'm changing an undefined location in memory and it's just the release build mode that doesn't check access violations?


You got it!
-----------------------------------------Everyboddy need someboddy!
Quote:Original post by someboddy
Quote:Original post by i_luv_cplusplus
if the data isn't allocated, I shouldn't be able to change it? Does that mean that I'm changing an undefined location in memory and it's just the release build mode that doesn't check access violations?


You got it!


Not quite. Access violations are checked by the OS so running in Release or Debug mode doesn't change anything.

What is actually happening is that running in Debug mode will cause non-active memory to be filled with certain patterns. For uninitialised memory will be set to a particular value. These values are highly likely to cause access violations if interpreted as an address. In release mode the values could be anything, including addresses that are valid inside the processes address space.


Quote:Original post by rip-off
Quote:Original post by someboddy
Quote:Original post by i_luv_cplusplus
if the data isn't allocated, I shouldn't be able to change it? Does that mean that I'm changing an undefined location in memory and it's just the release build mode that doesn't check access violations?


You got it!


Not quite. Access violations are checked by the OS so running in Release or Debug mode doesn't change anything.

What is actually happening is that running in Debug mode will cause non-active memory to be filled with certain patterns. For uninitialised memory will be set to a particular value. These values are highly likely to cause access violations if interpreted as an address. In release mode the values could be anything, including addresses that are valid inside the processes address space.


Yup! When I get a crash in debug or not release or vice-versa, I tend to start looking for the memory patterns. Once you've been programming for a while, when you see CDCDCDCD as a pointer and you try to dereference it, you'll instantly say "Doh!"

Obviously, differences between debug and release are much more than that. Hell, a few days ago a professor showed us a case where the VS2003 compiler generated the wrong code when it was in release (due to an error in their optimization). It was actually the first time I've seen a crash, not because of incorrect code written by the programmer, but bad code by the compiler! That story is for another thread though.

This topic is closed to new replies.

Advertisement