I'm working on a C++11 program, where security is important and my task is to set to 0 the used memory after erasing it.
I have an std::map mapping from int to an std::vector of pointer to class. I have the index in std::map and a pointer to the instance I would like to delete.
The following code produces the output I want, however, I'm not sure if it's good formed code (or I would say I'm not sure if this code is ok or not).
I have 2 questions.
If the following code is ok,
It can only be compiled with -fpermissive, I don't understand the compiler error message.
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
class MyClass
{
private:
int num;
public:
MyClass(int num) { this->num = num; }
int GetNum() const { return this->num; }
};
void PrintWorkingData(const std::map<int, std::vector<MyClass*>>& working_data, int idx)
{
std::cout << "working_data[" << idx << "] is an std::vector, size: " << working_data[idx].size() << ", containing the following items: " << std::endl;
for (std::vector<MyClass*>::const_iterator it = working_data[idx].begin(); it != working_data[idx].end(); it++)
{
std::cout << "(*it)->GetNum() = " << (*it)->GetNum() << std::endl;
}
}
int main()
{
MyClass* DeleteMyClass;
std::map<int, std::vector<MyClass*>> working_data;
working_data[0].push_back(new MyClass{4});
working_data[0].push_back(new MyClass{7});
working_data[1].push_back(new MyClass{11});
// the origonal code isn't like this; let's suppose
// we stored in the DeleteMyClass pointer the MyClass pointer
// that we would like to delete
working_data[1].push_back(DeleteMyClass = new MyClass{22});
working_data[1].push_back(new MyClass{33});
working_data[2].push_back(new MyClass{1000});
PrintWorkingData(working_data, 0);
PrintWorkingData(working_data, 1);
PrintWorkingData(working_data, 2);
PrintWorkingData(working_data, 3);
// so our task is to delete DeleteMyClass object from working_data[DeleteItemIndex]
// and fill with 0 where it was stored
int DeleteItemIndex = 1;
std::vector<MyClass*>::iterator pos = std::find(working_data[DeleteItemIndex].begin(), working_data[DeleteItemIndex].end(), DeleteMyClass);
if (pos == working_data[DeleteItemIndex].end())
{
std::cout << "Error: The item does not present in the working_data" << std::endl;
}
else
{
std::fill(pos, pos + 1, 0);
working_data[DeleteItemIndex].erase(pos);
delete DeleteMyClass;
std::cout << "The object successfully deleted" << std::endl;
}
PrintWorkingData(working_data, 0);
PrintWorkingData(working_data, 1);
PrintWorkingData(working_data, 2);
PrintWorkingData(working_data, 3);
return 0;
}
Setting a pointer value to nullptr doesn't change the data it points to. Erasing an element from a vector will overwrite that element with all the later ones in the vector, leaving (in this case) a second pointer in allocated memory (beyond the size of the vector) to the last element in the vector.
To erase the memory occupied by the object that DeleteMyClass points to, you'll have to handle the object destruction and memory freeing separately. This is not necessarily easy or straightforward, as there can be nuances (exception handling, array vs. non-array forms) that need to be addressed. You should also keep in mind that it is possible to inspect the memory of a running process, and view the data you're trying to erase while the object that uses it is live.
Here are several approaches that might work for you case.
One way to do this is to manually call the destructor, clear out the memory, then free it.
DeleteMyClass->~MyClass();
memset(DeleteMyClass, 0, sizeof(*DeleteMyClass));
delete (void *) DeleteMyClass;
The cast on the delete call is necessary to avoid calling the destructor, and the number of bytes to clear uses the type of DeleteMyClass, which will be incorrect if what is pointed to is a class derived from MyClass.
Another alternative is to use placement new with an already allocated memory buffer and a custom deallocator (after manually calling the destructor) to free up the memory.
A third possibility is to use custom new and delete functions, either for this specific class or globally.
Related
I am experimenting with Pointers and can't figure out why this won't work.
I know that I am supposed to be using STL containers instead of using raw pointers but I am curious as to why this is not working.
Suppose that we have a class like this
class Example
{
public:
Example()
:number{10}
{
std::cout << "From Example Class " << std::endl;
}
~Example()
{
std::cout << "Destructor from Example Class" << std::endl;
}
void print()
{
std::cout << "Number from Example : " << number << std::endl;
}
private:
int number{};
};
We initialize a pointer to array of pointers like this
// Pointer to array of pointers
Example** ex_ptr_array{ new Example * [4] };
for (size_t i = 0; i < 4; i++)
{
ex_ptr_array[i] = new Example{};
}
I can dereference a pointer by doing this and I can call the objects method without using -> operator.
(*ex_ptr_array[0]).print();
// Prints Number from Example : 10
I can also use the array style and use -> operator to call the objects method.
ex_ptr_array[2]->print();
// Prints Number from Example : 10
But I dont understand why the Pointer Arithmetic will not work
// Why doesnt this work?
(*ex_ptr_array + 1)->print();
// Prints some random value
// Number from Example : -33686019
(*ex_ptr_array + 1)->print();
You're dereferencing ex_ptr-array first, and then adding one. Do it the arithmetic before the dereference:
(*(ex_ptr_array + 1))->print();
The compiler knows the size of the type held in ex_ptr_array, so when you add 1 to the pointer, it actually increments the pointer by the size of that type.
I'm newbee about c++ and I'm having trouble with destructors. When i create an object and push to a vector that holds class, i can see variable "_path" is initialized. But after i try to reach the variable, i see object calls decontsuctor and i cant see the variable.
Here is the code:
#include <iostream>
#include <vector>
#include <string>
#include "ClassA.h"
A returnA(const char* char_a)
{
return A(char_a);
}
int main() {
std::vector<A> vectorA;
for (int i = 0; i < 10; i++)
{
std::string s = std::to_string(i);
vectorA.emplace_back(returnA(s.c_str()));
}
std::cout << "-------" << std::endl;
for (int i = 0; i < vectorA.size(); i++)
{
vectorA[i].getPath();
}
return 0;
}
class A
{
public:
const char* _path;
A(const char* path);
~A();
void getPath();
};
A::A(const char* path)
{
_path = path;
std::cout << "Obj is constructed! " << _path << std::endl;
}
A::~A()
{
std::cout << "Obj is deconstructed! ";
std::cout << _path << std::endl;
}
inline void A::getPath()
{
std::cout << _path << std::endl;
}
How can i prevent objects not deconstruct themselves and reach their variables without dynamic allocation?
std::string s = std::to_string(i);
vectorA.emplace_back(returnA(s.c_str()));
std::string's c_str() method returns a pointer to std::string's internal buffer that's no longer valid when the std::string gets changed in any way.
This std::string gets destroyed at the end of this for loop, and that certainly meets all "any way" requirements. This is how all objects work in C++. This std::string's gets declared inside a for loop, and it gets destroyed as soon as the end of the loop ends and it iterates again (or stops).
At this point accessing this pointer becomes undefined behavior, this is what you're seeing.
As far as destructor calls: this is completely unrelated, this is simply how vectors work. When objects get added to a vector they get moved or copied into the vector itself. Additionally, a vector resizes itself, as it grows, because that's what a vector is all about. If you add an object to a vector, and then destroy the original object you'll, obviously, see the destructor getting called:
vectorA.emplace_back(returnA(s.c_str()));
The temporary object returned from returnA gets copied/moved into the vector, here. Then this temporary object gets destroyed, and this is the destructor call you're seeing. But the vector continues to hold its copy of the emplaced object, safe and sound.
The simplest way to fix your undefined behavior is to simply replace the const char * member of your class with its own std::string (and just the parameter to the constructor accordingly. This is what std::strings for: as you move or copy them around they'll take care of all the housekeeping for you.
This, of course, won't change the destructor behavior or invocation, it does not affect that.
I have a task to create an object Stos which would feature a heap of objects Obiekt, to which I could add things as I please.
In order to make the program better support dynamic arrays I decided to use a Vector.
The whole implementation seems to run perfectly, the returned value is completely off.
Here is an example with code:
class Obiekt {
private:
int id;
public:
Obiekt::Obiekt(int i) {
id = i;
}
void Obiekt::display() {
cout << "This object has id of: " << id << endl;
}
};
class Stos {
private:
vector < Obiekt* > stos;
public:
Stos::Stos(Obiekt n) {
add(n);
}
void Stos::add(Obiekt n) {
stos.push_back(&n);
}
void Stos::display() {
cout << endl << "===HEAP DISPLAY===" << endl;
for (int i = 0; i < stos.size(); i++) {
stos[i]->display();
}
}
};
void Zad1()
{
Obiekt obj1(5);
Obiekt obj2(23);
Stos s1(obj1);
s1.add(obj2);
s1.display();
getchar();
}
And the outcome being:
===HEAP DISPLAY===
This object has id of: -858993460
This object has id of:9805925
I'm not a cpp expert, and believe the issue is related to the stos.push_back(&n) portion, but I can't catch the moment the id gets so distorted.
It's probably a noob question, so sorry for that on start.
Any help would be amazing.
The issue with your code as O'Neil correctly explained is that you're adding the pointer to a copy of the Obiekt object. So basically, you create your object in main, and pass it to the constructor and the .add function in Stos. You then add the pointer to the vector. When the function finishes, the copy that was passed is destroyed and the pointer in your vector is dangling.
There are two ways to fix this:
1 Pass by reference
This is very simple, basically you just add an ampersand to your function parameters. For instance:
void Stos::add(Obiekt &n) {
stos.push_back(&n);
}
This will ensure that the object isn't destroyed at the end of the function
2 Don't use pointers
Another way of getting your problem to work is to avoid using pointers at all. Your vector will actually copy the contents of the Obiekt object into it. For example:
vector < Obiekt > stos; // notice how we define it without the pointer type
...
void Stos::add(Obiekt n) {
stos.push_back(n); // Creates copy which will then contain the correct value
}
The parameters Obiekt n in
Stos::Stos(Obiekt n) {
add(n);
}
void Stos::add(Obiekt n) {
stos.push_back(&n);
}
are temporary copies destroyed immediatly after each call.
You have to use a reference Obiekt & n instead, or better: by pointer Obiekt * n.
I'm reluctant to assert that the objects exist at the time display is called.
Problem(s)
According to GCC's implementation they don't.
They fall out of scope and are immediately destructed. Give "Obiekt" a non-trivial destructor and this behavior becomes obvious:
~Obiekt(){std::cout << "Bye from: " << it << std::endl;}
Secondarily, note that you shouldn't specify the class membership for functions defined within the class itself (no class_name::function_name(parameters), just function_name(parameters) )
Possible Fix
You (might) want to changing "Stos" such that:
Stos(Obiekt &n) {add(n);}
void add(Obiekt &n) {stos.push_back(&n);}
I have a struct data
struct dataStruct{
int mID;
float mX;
};
a fillData method
void fillData(data *pt)
{
pt = new data(10);
}
and the main function
int main(int argc, char** argv)
{
dataStruct *myData;
fillData(myData);
myData[4].mID = 10;
std::cout << myData[4].mID << " " << myData[5].mID << std::endl;
}
and a couple of questions:
how can allocate myData inside the fillData method so that the allocation is not local to fillData?
Can the size of myData be increased by later calls to fillData and thus changing the size from i.e. 10 to 100 ?
Would it be better to manage the dataStruct pointer using std::unique_ptr ?
I am guessing at what you want, as it is not clear.
Here is a much better way to handle a collection of objects whose size needs to change dynamically:
struct dataStruct
{
dataStruct() : mID(0), mX(0.0f) {} // default to value 0
dataStruct(int mID, float mX) : mID(mID), mX(mX) {}
int mID;
float mX;
};
int main(int argc, char** argv)
{
std::vector<dataStruct> myData(10); // create 10 objects with values 0
myData[4].mID = 10;
std::cout << myData[4].mID << " " << myData[5].mID << std::endl;
// now resize to 100 objects, with 0 values for any new objects
myData.resize(100);
std::cout << myData[4].mID << " " << myData[99].mID << std::endl;
}
Live example:
http://ideone.com/5nyPOp
No memory leaks! No uninitialized data (which is used in your original code). And good debug compilers will bounds check for you.
For the first question, fillData() needs to accept either a reference
void fillData(data *&pt) // makes change of pt visible to the caller
{
pt = new data(10);
}
int main()
{
data *pointer;
fillData(pointer);
}
or a pointer to a pointer
void fillData(data **pt) // makes change of *pt visible to the caller
{
*pt = new data(10);
}
int main()
{
data *pointer;
fillData(&pointer); // pass the address of pointer
}
For the second question, somehow fillData() needs to be told how many objects to allocate, and be able to release.
void fillData(data *&pt, int size)
{
delete [] pt;
pt = new data[size];
}
int main()
{
data *pointer = NULL; // otherwise first call of fillData() will fail on the delete statement
fillData(10);
// use pointer like an array of 10 elements
fillData(20); // note previous contents of pointer are lost
// use pointer like an array of 10 elements
}
Answer to your third question: Short answer: No.
Longer answer to your third question: If you want a resizable set of your data, use a standard container (like std::vector<data>) instead. One advantage of this is that standard containers can be resized cleanly (e.g. if resizing from 10 to 20 elements, the first ten elements are retained).
Note: it is possible to resize things allocated directly with operator new (e.g. with additional book-keeping to keep track of current and new sizes) but I have not done it in the examples above - because using a standard container is a vastly better approach in practice.
I have a simple function that I simplified to return just a dummy list (to ensure its not some logic error)
vector<AttrValue>* QueryEvaluator::getCandidateList(...) {
...
values.clear();
values.push_back(2);
values.push_back(3);
cout << "values is of size " << values.size() << endl;
return &values;
}
then in a cppunit test:
vector<AttrValue>* candidateList0 = evaluator->getCandidateList(cl, 0);
cout << candidateList0->size() << endl;
But problem is size(), in the test, is always 0 even though the cout message prints the correct size 2. What might be wrong?
I tried a simple program and it appears to be fine ...
#include <iostream>
#include <vector>
using namespace std;
vector<int>* test() {
vector<int> vec { 2, 3, 6, 1, 2, 3 };
return &vec;
}
int main() {
cout << test()->size() << endl;
return 0;
}
You are returning a the address of temporary from getCandidateList function, the object is release when function returns. access to it is undefined behavior. You could just return the vector out, RVO should come to apply and elide the copy:
Try:
std::vector<AttrValue> QueryEvaluator::getCandidateList(...)
{
//blah
return values;
}
I tried a simple program and it appears to be fine ...
the temporary vector is released when getCandidateList function returns. The program has undefined behavior.
Your vector appears to be declared on the stack so will be destroyed when it goes out of scope (when the function exits). If you want to return a pointer to a vector, allocate it on the heap instead
vector<AttrValue>* QueryEvaluator::getCandidateList(...) {
vector<AttrValue>* values = new vector<AttrValue>();
...
values->clear();
values->push_back(2);
values->push_back(3);
cout << "values is of size " << values->size() << endl;
return values;
}
It might be easier to instead declare it in the caller and pass a reference to getCandidateList
void QueryEvaluator::getCandidateList(vector<AttrValue>& values)
...or return it by value
vector<AttrValue> QueryEvaluator::getCandidateList(...) {
So many interesting things to consider:
vector<AttrValue>* QueryEvaluator::getCandidateList(...) {
...
values.clear();
values.push_back(2);
values.push_back(3);
cout << "values is of size " << values.size() << endl;
return &values;
}
So it looks like you left out the most interesting piece in the code ... above. Moral of the story try and provide compilable working code that shows the error. Reducing your problem to a small example usually results in you finding the problem yourself. At the very least you should provide exact definitions of all objects that are used (the type is the most important thing in C++)
Does it declare the vector as a local object?
std::vector<int> values;
In this case the vectors lifespan is bound to the function and it is destroyed at the end of the function. This means using it after the function has returned is undefined behavior (anything can happen).
But it also looks like you are using objects as part of you unit test framework. So a potential solution is to make the vector part of the object. Then the vector will live as long as the object (not just the function call) and thus returning a pointer to it will work as expected.
class QueryEvaluator
{
std::vector<int> values;
public:
vector<AttrValue>* QueryEvaluator::getCandidateList(...);
};
An alternative would be to return the vector by value rather than a pointer. This means the object will be correctly copied out of the function and your calling code can manipulate and test the vector all they need.
vector<AttrValue> QueryEvaluator::getCandidateList(...)
{
...
return &values;
}
Side Note:
Also you need to try not to use pointers in your code. Pointers doe not convey any ownership.This means we do not know who is responsible for deleting the object. In this case a reference would probably have been better (you never return NULL) as this gives the caller access to the object will retaining ownership (assuming you decided not to return by value).