Strange behaviour with a vector of pointers

2019-09-23 05:54发布

问题:

I'm having a bit of trouble understanding the output that I get when I run this simple piece of code

#include <vector>
#include <iostream>
#include "LxUNIXsys.h"
using namespace std;

int main(int argc, char** argv) {

  //memory management class
  LxUNIXsys mem_manager;

  vector <double*> vec;

  mem_manager.DumpMemoryInfo();getchar();
  for(int i =0; i < 3; i++) vec.push_back(new double (3));
  for(int i =0; i < vec.size(); i++) cout << *vec[i] << endl;
  mem_manager.DumpMemoryInfo();getchar();
  for(int i =0; i < vec.size(); i++) delete vec[i];
  vec.clear();
  for(int i =0; i < 3; i++) cout << *vec[i] << endl;
  cout <<"size of vec " <<vec.size() << endl;
  mem_manager.DumpMemoryInfo();

  return 0;
}

The LxUNIXsys is a class that I'm using for the memory dump and the method I'm calling from it is:

void LxUNIXsys::DumpMemoryInfo() {

  pid_t id = getpid();
  //  cout << "id = " << id << endl;
  stringstream ss("");
  ss << "pmap -d " << id  << " | grep private ";
  //  cout << ss.str().c_str() << endl;
  cout << "Memory dump: [pid = " << id << " ] " << flush; system(ss.str().c_str());
}

The Output I'm getting is:

Memory dump: [pid = 17012 ] mapped: 51476K    writeable/private: 7452K    shared: 0K

3
3
3
Memory dump: [pid = 17012 ] mapped: 51480K    writeable/private: 7456K    shared: 0K

3
3
3
size of vec 0
Memory dump: [pid = 17012 ] mapped: 51480K    writeable/private: 7456K    shared: 0K

So, basically I deleted the pointer and not only the information is still there but I can access it after clear().

I have also tried to delete vec using delete[] but the result is the same.

PS: I know about the existence of smart pointers, but I want to know why this code does not do what's expected.

PPS: I know about the undefined behavior, forget about the accessing after clear, I just want an effective way to release the memory immediately, like when I delete a regular pointer.

回答1:

You have undefined behaviour. This is caused by you accessing elements of your std::vector that just don't exist. Undefined behaviour means that anything can happen. It can even appear that objects that should have been destroyed are still there.

The C++ standard says nothing about how the operating system should manage the allocation and deallocation of memory. It simply gives rules about what your program can rely on. There's no reason that the memory allocated for those three doubles couldn't actually be reclaimed by the OS a little later than you asked for it to be. You just can't rely on it any more. The only thing you can rely on is that you should not be accessing outside the bounds of your std::vector.

This is precisely why this is specified by the standard as undefined behaviour. It gives the operating system or environment the leeway to perform its memory management however it chooses, while still giving your program that rules to rely on for well-defined behaviour.



回答2:

Deleting memory that was allocated from the free store is not guaranteed to return it to the operating system, or to make it inaccessible. Typically, small allocations are managed by a heap within your process; it allocates a large lump from the system, and allocates smaller pieces of that; deleted memory is returned to that heap. This can be much more efficient than going to the system for every allocation.

This means that deleted memory may still be accessible and, until it's reused, may still contain whatever data was there when it was deleted. So accessing it gives undefined behaviour, not any well-defined error.



回答3:

I think the problem is the way you are reading your vector:

for(int i =0; i < 3; i++)

With this line you are reading beyond the end of the vector. Even if it's content is deleted, it may stay in memory for a while. This means that once it is deleted, you can no longer be sure that what is hold in those positions is what was stored before deletion, but it CAN be what you stored.

It's like deleting a file from your HD. The bits ar eactually there until rewritten, they are just set as unused.