Deleting the double pointer is will cause the harmful effect like crash the program and programmer should try to avoid this as its not allowed.
But sometime if anybody doing this then i how do we take care of this.
As delete in C++ is noexcept operator and it'll not throw any exceptions. And its written type is also void. so how do we catch this kind of exceptions.
Below is the code snippet
class myException: public std::runtime_error
{
public:
myException(std::string const& msg):
std::runtime_error(msg)
{
cout<<"inside class \n";
}
};
void main()
{
int* set = new int[100];
cout <<"memory allcated \n";
//use set[]
delete [] set;
cout <<"After delete first \n";
try{
delete [] set;
throw myException("Error while deleting data \n");
}
catch(std::exception &e)
{
cout<<"exception \n";
}
catch(...)
{
cout<<"generic catch \n";
}
cout <<"After delete second \n";
In this case i tried to catch the exception but no success.
Pleas provide your input how we'll take care of these type of scenario.
thanks in advance!!!
Given that the behaviour on a subsequent delete[] is undefined, there's nothing you can do, aside from writing
set = nullptr;
immediately after the first delete[]. This exploits the fact that a deletion of a nullptr is a no-op.
But really, that just encourages programmers to be sloppy.
Segmentation fault or bad memory access or bus errors cannot be caught by exception. Programmers need to manage their own memory correctly as you do not have garbage collection in C/C++.
But you are using C++, no ? Why not make use of RAII ?
Here is what you should strive to do:
Memory ownership - Explicitly via making use of std::unique_ptr or std::shared_ptr and family.
No explicit raw calls to new or delete. Make use of make_unique or make_shared or allocate_shared.
Make use of containers like std::vector or std::array instead of creating dynamic arrays or allocating array on stack resp.
Run your code via valgrind (Memcheck) to make sure there are no memory related issues in your code.
If you are using shared_ptr, you can use a weak_ptr to get access to the underlying pointer without incrementing the reference count. In this case, if the underlying pointer is already deleted, bad_weak_ptr exception gets thrown. This is the only scenario I know of when an exception will be thrown for you to catch when accessing a deleted pointer.
A code must undergo multiple level of testing iterations maybe with different sets of tools before committing.
There is a very important concept in c++ called RAII (Resource Acquisition Is Initialisation).
This concept encapsulates the idea that no object may exist unless it is fully serviceable and internally consistent, and that deleting the object will release any resources it was holding.
For this reason, when allocating memory we use smart pointers:
#include <memory>
#include <iostream>
#include <algorithm>
#include <iterator>
int main()
{
using namespace std;
// allocate an array into a smart pointer
auto set = std::make_unique<int[]>(100);
cout <<"memory allocated \n";
//use set[]
for (int i = 0 ; i < 100 ; ++i) {
set[i] = i * 2;
}
std::copy(&set[0], &set[100] , std::ostream_iterator<int>(cout, ", "));
cout << std::endl;
// delete the set
set.reset();
cout <<"After delete first \n";
// delete the set again
set.reset();
cout <<"After delete second \n";
// set also deleted here through RAII
}
I'm adding another answer here because previous answers focus very strongly on manually managing that memory, while the correct answer is to avoid having to deal with that in the first place.
void main() {
std::vector<int> set (100);
cout << "memory allocated\n";
//use set
}
This is it. This is enough. This gives you 100 integers to use as you like. They will be freed automatically when control flow leaves the function, whether through an exception, or a return, or by falling off the end of the function. There is no double delete; there isn't even a single delete, which is as it should be.
Also, I'm horrified to see suggestions in other answers for using signals to hide the effects of what is a broken program. If someone is enough of a beginner to not understand this rather basic stuff, PLEASE don't send them down that path.
Related
I'm using a library that, in order to construct some object that I use, expects a raw pointer to an object. I'm not sure what it will do with the pointer, to make my code as safe as possible, what should I pass to this function?
Use a unique pointer - if they decide to delete the pointer, I will do a double-delete
Keep track of a raw pointer - bad because I have to remember to write delete, but it could still be a double-delete
Use auto duration and give them a pointer Give them a reference - their code will error if they call delete
Use a shared pointer - same double-delete problem as unique pointer, but now my scope won't hurt their pointer
Based on my reading, option 3 seems like what I should do - they shouldn't be calling delete on the pointer, and this format enforces that. But what if I don't know whether they now or in the future will call delete on the reference I gave them? Use a shared pointer and say "not my fault about the double delete"?
#include <memory>
#include <iostream>
class ComplexObj {
public:
ComplexObj() : m_field(0) {}
ComplexObj(int data) : m_field(data) {}
void print() { std::cout << m_field << std::endl; }
private:
int m_field;
};
class BlackBox {
public:
BlackBox(ComplexObj* data) {
m_field = *data;
// Do other things I guess...
delete data;
std::cout << "Construction complete" << std::endl;
}
void print_data() { m_field.print(); }
private:
ComplexObj m_field;
};
int main(int argc, char* argv[]) {
// Use a smart pointer
std::unique_ptr<ComplexObj> my_ptr(new ComplexObj(1));
BlackBox obj1 = BlackBox(my_ptr.get());
obj1.print_data();
my_ptr->print(); // Bad data, since BlackBox free'd
// double delete when my_ptr goes out of scope
// Manually manage the memory
ComplexObj* manual = new ComplexObj(2);
BlackBox obj2 = BlackBox(manual);
obj2.print_data();
manual->print(); // Bad data, since BlackBox free'd
delete manual; // Pair new and delete, but this is a double delete
// Edit: use auto-duration and give them a pointer
ComplexObj by_ref(3);
BlackBox obj3 = BlackBox(&by_ref); // they can't call delete on the pointer they have
obj3.print_data();
by_ref.print();
// Use a shared pointer
std::shared_ptr<ComplexObj> our_ptr(new ComplexObj(4));
BlackBox obj4 = BlackBox(our_ptr.get());
obj4.print_data();
our_ptr->print(); // Bad data, they have free'd
// double delete when our_ptr goes out of scope
return 0;
}
Other questions I read related to this topic...
unique_ptr.get() is legit at times
I should pass by reference
I think I am case 2 and should pass by reference
You cannot solve this problem with the information you have. All choices produce garbage.
You have to read the documentation of the API you are using.
Doing any of your 4 answers without knowing if they take ownership of the pointer will result problems.
Life sometimes sucks.
If you have a corrupt or hostile API, the only halfway safe thing to do is to interact with it in a separate process, carefully flush all communication, and shut down the process.
If the API isn't corrupt or hostile, you should be able to know if it is taking ownership of the pointed to object. Calling an API without knowing this is a common mistake in novice C++ programmers. Don't do it. Yes, this sucks.
If this API is at all internal and you have any control, seek to make all "owning pointer" arguments be std::unique_ptr<>s. That makes it clear in the API that you intend to own the object and delete it later.
I'm learning C++ and I ran into a bit of code that I'm confused on what exactly it does. I'm learning dynamic memory and the place I'm learning it from mentioned that this was good practice.
double * pvalue = NULL;
if(!(pvalue = new double)){
cout<<"Error: out of memory." << endl;
exit(1);
}
I understand that you are creating a pointer called pvalue, but I don't understand the if statement. If someone could explain it to me I'd be greatly appreciated.
I'm confused on what exactly it does.
Working with a very outdated notion and limited understanding of C++.
First of all, C++ does not report a failure to allocate memory by returning NULL. It throws an exception, of type std::bad_alloc (which is derived from std::exception).
Second, with the advent of C++11, using "naked" pointers like that is frowned upon, because they all-too-easily result in resource leaks when you forget to delete them, e.g. when an unexpected exception makes your pointer go out of scope.
So you really should use either std::shared_ptr<> or unique_ptr<>.
pvalue = new double // This allocates a dynamic double as usual
!(pvalue = new double) // This takes the value of the resulting pointer
// and negates it, checking whether it's null
if(!(pvalue = new double)) // It all becomes the condition for the if.
It's worth noting that:
Raw owning pointers must not be used in C++, use smart pointers instead;
using namespace std; (which I'm certain this sample has) must not be used;
Dynamically allocating a single double is weird;
Plain new will never return a null pointer, so the check is meaningless;
std::exit will nuke your program mid-flight, leaking all objects with automatic lifetime, return from main instead.
[...] the place I'm learning it from mentioned that this was good practice.
It's time to put on some heavy metal and sunglasses, set fire to "the place" and go find some better learning material.
This:
if(!(pvalue = new double)){
... is just a (perhaps-too) clever shorthand way of writing this:
pvalue = new double;
if (pvalue == NULL) {...}
new never returns nullptr unless you provide std::nothrow. Rather, if new fails it will throw std::bad_alloc.
The more appropriate solution would be something like :
#include <iostream>
#include <stdexcept>
double * foo()
{
double * pvalue = nullptr;
try {
pvalue = new double;
}
catch(const std::bad_alloc &) {
std::cout << "Error: out of memory." << std::endl;
exit(1);
}
return pvalue;
}
However, using raw owning pointers is discouraged in modern code. new is generally avoided in favor of std::make_unique or std::make_shared. For example, an better solution would be something like this :
#include <iostream>
#include <memory>
#include <stdexcept>
std::unique_ptr<double> foo()
{
try {
return std::make_unique<double>();
}
catch(const std::bad_alloc &) {
std::cout << "Error: out of memory." << std::endl;
exit(1);
}
}
First off, this is not a duplicate. My question is how to do it with dynamic memory. The reason this is distinct is because my delete[] is hanging.
So, here's what I have:
class PacketStrRet {
public:
PacketStrRet(char p_data[], int p_len) : len(p_len) {
data = new char[p_len];
memcpy(data, p_data, p_len * sizeof(char));
}
~PacketStrRet() {
delete[] data;
data = nullptr;
}
char* data;
int len;
};
And yes, I'm aware that my code is not using the best practices. I'll clean it up later.
The problem I'm having is in the DTOR. That delete is hanging forever. The data being passed in to the CTOR is not dynamic memory, so I need to make it dynamic so things don't go out of scope. p_len holds the correct amount of data, so there's no problem there.
From what I've read, memcpy seems to be the most likely culprit here. So how do I copy a string that is not null-terminated to dynamic memory, and then still be able to delete it later?
Thanks.
The problem is not the delete, only everything that comes before and even that would be ok if there didn't occur any problems.
class PacketStrRet {
// Use RAII
std::unique_ptr<char> data; // I own this data and will destroy it.
// now the parent class is also only movable, use shared_ptr if you can't live with that.
int len;
public:
PacketStrRet(
// <RED ALERT>
char p_data[], int p_len // user can lie to us.
// </RED ALERT>
) try : // function try block, se 1)
len(p_len), data(new char[p_len]) {
memcpy(data, p_data.get(), p_len * sizeof(char));
} catch(const std::exception& e) {
std::cerr << "arg=" << arg << " failed: " << e.what() << '\n';
}
~PacketStrRet() {
// unique_ptr takes care of memory management and garbage collection.
}
// access functions
};
Now the possible errors you could make to blow the code up.
You could have copied the object, essentially making two owning raw pointers to the same data. This would blow up at delete, you coudl use memory-sanitizer / valgrind to confirm this happens. Use smart pointers to save you the trouble, the unique pointer should cause a compiler error if you tried to copy, unless you memcpy the entire structure ignoring the copy/assignment constructors.
You could give the wrong len to the constructor, what is the source of the data and len? Valgrind / memory-sanitizer can save you.
The memory corruption could happen in a totally different place. Valgrind / memory-sanitizer can save you.
In case valgrind mem-san are too much, you can try to make a check for double delete, if you make a counter in c'tor and d'tor and if it ever goes to negative you have your error.
In this class your at least missing a copy constructor. Check up on rule of 3, 5, 7 and 0 (zero) to find out how many you need.
1) http://en.cppreference.com/w/cpp/language/function-try-block
Try to use std:: copy(). It will be like this:
std::copy(p_data, p_data + p_len, data).
1) Do we need to have a pointer validation for following code in cli. Is it good to have?
NameClass NameString^ = gcnew NameClass();
if (NameClass)
{
// some process
2) If we created a memory in one function and passing as pointer to other do we need to have validation ?
foo()
{
try {
NameClass *pNameString = new NameClass();
foo_2(pNameString);
} catch(std::bad_alloc &error)
{
std::cout << error.what() << std::endl;
}
}
foo_2(NameClass *pNameString)
{
if (pNameString) // do we need to validate here ?
{
// some stuff
}
}
3) Do we need to validate locally created object in reference passing ?
NameClass objNameClass;
foo(&objNameClass);
foo(NameClass *objNameClass)
{
if (objNameClass) // do we need to validate here ?
{
It's just as unnecessary just after a gcnew as it is after a new. It's only necessary if you use C allocators like malloc for some reason. The C++ and C++/CLI constructs use exceptions for unsuccessful object creations, unlike the C functions which return a null pointer.
In plain C++, new will throw std::bad_alloc if memory cannot be allocated. In C++/CLI, gcnew will throw System::OutOfMemoryException in that case.
Is most cases, you probably should let the exception propagate and kill your program, because it's probably doomed anyway.
In your second example, you may want to validate the pointer in foo_2 only if you expect someone to call foo_2 with a null pointer, and when that is a valid usage. If it's invalid usage to pass it a null pointer as an argument, then you have a bug and should probably let your application crash (instead of letting it corrupt your data for instance). If foo_2 is only visible to the code which calls it immediately after allocation, it's unnecessary as it won't ever be null.
Same for the third example. The contract/documentation of your function should specify whether it is valid to call it with a null pointer, and how it behaves.
And please, don't ever write that:
catch(std::bad_alloc &error)
{
std::cout << error.what() << std::endl;
}
If you have a low memory condition on a regular object allocation, just let your program die. Trying to cure it that way won't get you very far.
The only place when such code would be acceptable IMHO is when you're trying to allocate a potentially big array dynamically, and you know you can just cancel that operation if you're unable to do so. Don't attempt to catch allocation errors for every allocation, that will bloat your code and lead you nowhere.
I have programmed a little software and wanted to create a new object on the heap. In the class member function I thus have
void gShop::CreateCustomer(int type, int number)
{
vSlot[number] = new gCustopmer(type);
vSlot[number]->itsContactToShop=itsShopNumber;
vSlot[number]->itsNumber=number;
}
where vSlot is a vector of pointers to customer objects. I have a (here: abbreviated) class gShop, in essence:
class gShop : public gBranch
{
public:
gShop(): vSlot(100){}
~gShop(){}
std::vector <gCustomer*> vSlot;
...
}
and in main I call the member function to create new customers..
vShop[0].CreateCustomer(TYPE_M20, 1);
vShop[0].CreateCustomer(TYPE_F40, **2**);//EDIT:typo previously here. I intend to create customers by reading a file later on.
std::cout<< "1" << vShop[0].vSlot[1]->itsTypeString << std::endl;
std::cout<< "2" << vShop[0].vSlot[2]->itsTypeString << std::endl;
I know that I have created with "new" two objects on the "heap" (if I handle the terminology right - sorry I am quite new to programming without formal education) and I also have two pointers to that objects stored in a vector within the object shop[0].
My question is I heard the saying that for every new there is a delete. Where do I have to delete this object? I am actually not planning on deleting any created shop or customer object in the program.
Secondly, is this code so far okay in terms of not causing memory leaks? I am a bit worried that I created the new object within a member function class, so should I try to implement delete in the destructor to gShop and set the pointer to NULL - in the theoretical case I should ever want to delete shop[0]?
Many thanks.
In the way you have written your code, you should expand you destructor implementation for gShop to iterate over the vector<> vSlot and delete each element. Because you have memory that has to be managed in this way to prevent a memory leak, you are also required to follow the Rule of Three. So, you also need to do something during copy construction (a deep copy), and you have to do something for the assignment operator (cleanup up the vector<> that is about to be copied over, and do a deep copy).
You can avoid these issues, and allow your object to use the default destructor, copy constructor, and assignment operator, by using a smart pointer instead. For example:
std::vector<std::shared_ptr<gCustomer>> vSlot;
When you create an element in the vSlot, you could use make_shared():
vSlot[number] = std::make_shared<gCustopmer>(type);
The smart pointer will delete the memory for you when there are no more references to the memory. If you don't have C++.11 available to you, you can use boost::shared_ptr instead.
The smart pointer will make it so that a copy of your gShop will share the same pointers as the original gShop it copied from. The smart pointer makes that situation okay, since there will not be multiple delete calls on the same memory. However, if you need the deep copy semantics, then you would still need to implement your own copy constructor and assignment operator to make the deep copies.
If you want something that will clean up automatically like a smart pointer, but still give you a deep copy with the default copy constructor and default assignment operator, then you can try to use boost::optional.
If you are using g++ version 4.4 or higher, then you should be able to enable C++.11 features with -std=gnu++0x, or -std=c++0x if you don't want GNU extensions. If you have g++ 4.7 or higher, then the options are -std=gnu++11 or -std=c++11.
Every time you create object with new piece of memory is taken from the heap. Only way to communicate with this memory is via pointer you got from new. When you use delete on that pointer memory is freed and may by used for other purposes. So when you lose pointer you create memory leak.
In your code the right way is:
Start with the vector with null pointers.
When you create object in exact position check pointer. If it is not null you already have object and have to delete it (or maybe throw error)
void gShop::CreateCustomer(int type, int number)
{
if(vSlot[number] != 0) {
delete vSlot[number];
vSlot[number] = 0;
}
vSlot[number] = new gCustopmer(type);
vSlot[number]->itsContactToShop=itsShopNumber;
vSlot[number]->itsNumber=number;
}
When the vector is destroyed you need to free all memory within it. So you destructor will be something like this:
gShop::~gShop() {
for(int i = 0; i < (int)vSlot.size(); ++i) {
delete vSlot[i];
}
}
Yes any memory that is allocated from the heap must be freed!
With the "new" you are allocating memory from the heap that is the sizeof gCustomer.
A good place to deallocate your memory would be in your destructor: ~gShop()
Memory leaks are caused by not deallocating your memory, although once your close your program all the memory is freed automatically.
gShop needs to delete the gCustomer objects that it creates. It can do that in its destructor, eg:
class gShop : public gBranch
{
public:
...
~gShop()
...
};
gShop::~gShop()
{
std::vector<gCustomer*>::iterator iter = vSlot.begin();
std::vector<gCustomer*>::iterator end = vSlot.end();
while (iter != end)
{
delete *iter;
++iter
}
}
Or:
void deleteCustomer(gCustomer *customer)
{
delete customer;
}
gShop::~gShop()
{
std::for_each(vSlot.begin(), vSlot.end(), deleteCustomer);
}
However, you would still have a memory leak. You are storing two separate gCustomer objects in the same vSlot[1] slot of vShop[0], so you are losing track of one of your customers. I suspect you meant to do this instead:
vShop[0].CreateCustomer(TYPE_M20, 1);
vShop[0].CreateCustomer(TYPE_F40, 2); // <-- was previously 1
std::cout<< "1" << vShop[0].vSlot[1]->itsTypeString << std::endl;
std::cout<< "2" << vShop[0].vSlot[2]->itsTypeString << std::endl;
That being said, you should re-think your design and let the STL handle all of the memory management for you, eg:
class gShop : public gBranch
{
public:
std::vector <gCustomer> vSlot;
...
};
void gShop::CreateCustomer(int type)
{
vSlot.push_back(type);
gCustomer &cust = vSlot.back();
cust.itsContactToShop = itsShopNumber;
cust.itsNumber = vSlot.size()-1;
}
vShop[0].CreateCustomer(TYPE_M20);
vShop[0].CreateCustomer(TYPE_F40);
// remember that vectors are 0-indexed
std::cout<< "0" << vShop[0].vSlot[0].itsTypeString << std::endl;
std::cout<< "1" << vShop[0].vSlot[1].itsTypeString << std::endl;
Or:
class gShop : public gBranch
{
public:
std::vector <std::shared_ptr<gCustomer> > vSlot;
...
};
void gShop::CreateCustomer(int type)
{
std::shared_ptr customer = std::make_shared<gCustomer>(type);
customer->itsContactToShop = itsShopNumber;
customer->itsNumber = vSlot.size();
vSlot.push_back(customer);
}
vShop[0].CreateCustomer(TYPE_M20);
vShop[0].CreateCustomer(TYPE_F40);
std::cout<< "0" << vShop[0].vSlot[0]->itsTypeString << std::endl;
std::cout<< "1" << vShop[0].vSlot[1]->itsTypeString << std::endl;