Consider I have the function:
int &create_ptr(){
int *x = new int;
*x =5;
return *x;
}
int main(){
int y = create_ptr();
}
Will this cause a memory leak or is there somehow to delete it?
Sorry if it's a basic question, this has just been bugging me and I couldn't really find the answer.
Thank you everyone, makes sense now!
To satisfy your curiosity, yes you can delete it safely, but only if you return it by reference (pointer or C++ reference (&)). By reference so as to retain the original address of your newed object. You need that address for you to correctly and safely delete your object.
int& create_ref(){
int *x = new int;
*x =5;
return *x;
}
int* create_ptr(){
int *x = new int;
*x =5;
return x;
}
int create_sane_version() {
return 5;
}
int main(){
int& x = create_ref();
delete &x; // OK. Get address of x; same as deleting through a pointer pointing to its address
// x here refers to the newed object inside create_ref() (*x)
// Still begs the question of why you're painstakingly doing this
int* y = create_ptr();
delete y; // OK, but not optimal (the above isn't either)
// * not optimal == a bad way to do this
int leak = create_ref();
delete &leak; // DEFINITELY NOT OK. leak isn't the same as the newed object
// i.e. &leak != &create_ref();
// You're actually *copying* the object referred to by the returned
// reference. The returned reference gets lost.
int best_way_to_do_this = create_sane_version();
}
Will this cause a memory leak?
Yes, it will. You are allocating dynamic memory with the new statement with no corresponding delete to free it, ergo: you have a memory leak.
Is there somehow to delete it?
Of course there's: don't do dynamic memory allocation with naked pointers. In your case, why do you even need a reference at all?
int create(){
return 5;
}
int main(int, char*[]){
int y = create();
}
If you really need dynamic memory you can use std::shared_ptr and std::make_shared like this:
#include <memory>
auto create_ptr() {
return std::make_shared<int>(5);
}
int main(int, char*[]) {
std::shared_ptr<int> y = create_ptr();
}
Yes, this will create a memory leak. You allocate space with new, but never free it using delete.
If you want to create an object (or a primitive type) on the free store, you can return a pointer, and make the function caller for deleting the pointed-to object.
// Caller is responsible for deleting pointed-to int.
int* create_ptr()
{
// Hope that operator new does not throw std::bad_alloc
int* x = new int;
*x = 5;
return x;
}
A better approach would be to return a smart pointer, but that it outside the scope of this question.
Since you create memory on heap int *x = new int;, You need to explicitly delete it.
You can use shared pointers if you want to avoid track of all heap memory and deleting it explicitly.
Shared pointers keep track of all reference to a memory when last reference goes out of scope, memory pointed is deleted.
Related
Is the following code snippet correct, or what could be wrong with it?
As I know, memory allocated with new, will not be erased unless there is a delete so returning its pointer should be fine?
// Example program
#include <iostream>
#include <string>
int* a()
{
int* aa = new int(1);
*aa = 44;
return aa;
}
int main()
{
int *aa = a();
printf("%d ", *aa);
}
It's not ideal. Who is responsible for deleting the pointer? You don't delete it anywhere in the example, so there is a memory leak.
Typically, if you need dynamic allocation, then you should return a smart pointer instead. That said, its usually also best to avoid unnecessary dynamic allocation. There's probably never a need to dynamically allocate a single int.
I am working on a project meant to understand memory management using C++,
Inside a function, if I create a new array of Student objects, do function stuff, and then return a pointer to the array like so:
int main(){
Student *ptr = new newStudents[50];
Student p.FunctionCall(ptr);
//stuff
delete[] ptr;
return 0;
}
I will then instantiate the object (make a copy) in main, and other class methods perhaps too, taking care to call delete[] after every usage.
Will it cause a memory leak to pass the heap pointer from function back into main and or other funcs as long as I remember to call delete from the last place it existed?
Constraints: no smart pointers, no namespace and no C++ 11 or higher.
It's for an assignment. All help appreciated.
Correct syntax would be:
MyClass* function(const char* file) {
MyClass *x = new MyClass[50]; //class_type* array_name = new class_type[amount];
//stuff to parse values and then instantiate my classes
return x; // return x directly as a pointer..
}
First.. Do NOT dereference the pointer you got from new and return it, because it's not a pointer to a pointer or pointer to an instance. It's literally a pointer to memory of an array and by dereferencing it, you will be returning an instance and losing the rest.. resulting in a leak.
So with that your of the way, you can now do:
int main()
{
MyClass* array = function("some_file.txt");
// do something with the array above..
delete[] array; //clean up..
}
Yes.
char* allocate_buffer() {
return new char[10];
}
int main() {
auto buf = allocate_buffer();
delete [] buf;
}
No memory leaks. You should use std::array or std::vector instead of managing memory manually.
I was just a little confused why the same memory address was being printed when I attempted to delete a newly allocated variable through a function, I am guessing that no memory was leaked or pointer dangled.
The same memory address was printed.
#include <iostream>
using namespace std;
void deallocater(int *p)
{
delete p;
p = nullptr; // memory deleted and no dangling pointer right?
}
int main()
{
int *x = new int(1);
cout<<x;
deallocater(x);
cout<<endl<<x; // why is the same memory address being printed?
return 0;
}
I'm assuming that the function worked successfully
Calling the function
void deallocater(int* p)
{
delete p;
p = nullptr;
}
via
deallocater(x);
copies the value of x to p. Thus within deallocater() the local variable p is assigned nullptr. However, the variable x of the calling program is not altered.
You may achieve what you appear to want by taking the argument by reference:
void deallocater(int* &p)
{
delete p;
p = nullptr;
}
However, memory allocation and de-allocation should not be split apart into different and unrelated functions to avoid the danger of dangling pointers and/or memory leaks. Instead, good C++ code contains hardly any delete statements and few new statements (to initialize smart pointers), but instead use standard library constructs (containers and smart pointers) for memory management.
The code cannot change the content of the pointer p in deallocater(), thus it still shows the same value when printed. After the call p still has the same (pointer) value, but the memory it points to is freed. This is known as a "dangling reference".
To update the pointer, use a double-pointer, or a reference to a pointer:
void deallocater(int **p)
{
delete *p;
*p = nullptr; // memory deleted and no dangling pointer right?
}
int main()
{
int *x = new int(1);
cout<<x;
deallocater( &x );
cout<<endl<<x; // why is the same memory address being printed?
return 0;
}
Consider the code snippet in C++:
int *foo() {
int *y = new int[1000];
return y;
}
int main() {
int *x = new int [1000];
x = foo();
delete[] x;
return 0;
}
When x is created it points to a memory address. When foo() is called, a new pointer y is created, pointing to a different address, but x is then set to the address that y had. So when it is deleted, the new address's memory is freed, but the original address that x had is leaked. Is that correct?
Furthermore, I made a slight change to the snippet by calling delete[] x before calling foo() and it still compiled and ran:
int *foo() {
int *y = new int[1000];
return y;
}
int main() {
int *x = new int [1000];
delete[] x;
x = foo();
delete[] x;
return 0;
}
Does this mean I prevented the leak? And one final question, if I do not initialize x when I declare it, but do not prematurely delete it, is it pointing to memory that will be leaked? Like below:
int *foo() {
int *y = new int[1000];
return y;
}
int main() {
int *x;
x = foo();
delete[] x;
return 0;
}
As a side note, I understand that using a vector and/or unique pointers is safer, but I'm curious as to the functionality of the code above, specifically what happens when a pointer is declared but initialized later.
When x is created it points to a memory address. When foo() is called, a new pointer y is created, pointing to a different address, but x is then set to the address that y had. So when it is deleted, the new address's memory is freed, but the original address that x had is leaked. Is that correct?
Yes.
Does this mean I prevented the leak?
Yes.
And one final question, if I do not initialize x when I declare it, but do not prematurely delete it, is it pointing to memory that will be leaked?
No.
As a side note, I understand that using a vector and/or unique pointers is safer
Absolutely. Even without those your code could be a lot clearer about memory ownership such that your question wouldn't even arise, but it's true that switching to standard containers/smart pointers would solve the problem right at the source, and I strongly recommend this.
tl;dr: you're right about everything so far
In your snippet above:
int *x = new int [1000];
x = foo();
delete[] x;
You allocated an array pointer to x, but then "squished" it by assigning foo() to it. If you were working in a garbage collected language (or using a smart pointer), the memory would have been reclaimed in that case.
I have noticed that if i create a pointer in a function, it won't let me set a value to it.
for example:
int func() {
int* pointer;
*pointer = 0 //error I get: "Exception: STATUS_ACCESS_VIOLATION"
return *pointer;
}
I get that not letting you set a pointer in the function because if I use a normal int it works:
int func() {
int notAPointer;
notAPointer = 0;
return notAPointer;
}
Can anyone explain to me why that is?
You haven't assigned any memory for your pointer to point to.
That means that dereferencing the pointer (*pointer) causes undefined behavior (like a crash in your case). You need to initialize the pointer before dereferencing it:
int* pointer = new int;
(And afterwards, delete pointer; to not leak the memory. Always delete everything you get from new.)
Also, pointers don't have to point to dynamically allocated data (acquired by a call to new), you can point to automatic (stack) variables too:
int func() {
int valueOnStack = 42;
int* pointer = &valueOnStack;
*pointer = 0;
return *pointer;
}
Because when you declare pointer it is pointing to a completely arbitrary memory location. You can't just write to any old piece of memory.
You need to allocate memory for it first:
int* pointer = new int;
*pointer = 0;
Or just:
int* pointer = new int();
The pointer pointer is uninitialized and points to a random location in memory when you declare it. It could be pointing into the system stack, or the global variables, or into the program's code space, or into the operating system. When you say *pointer = 0;, the program will simply try to write a 0 to whatever random location pointer points to.
The program may explode immediately, or may wait half an hour and then explode, or it may subtly corrupt data in another part of your program and you may never realize it. This can make this error very hard to track down. Make sure you initialize all pointers to a valid address before dereferencing them.
pointer does not point to anything following int* pointer;
So the behaviour of dereferencing it is undefined.
If you'd written
int n;
pointer = &n;
then you could dereference it.
Altenatively, you can allocate memory to it from the heap:
pointer = new int;
But you must remember to call delete pointer; else you'll leak memory.
This code is completely valid inside a function:
int *pointer = 0;
BUT, it would be the same as setting a pointer to the NULL macro.
If you try to set another value the compiler is going to complain that there is no valid conversion from int to int*:
int *pointer = 1; // Error
However, if you want to assign a value to the pointer, follow TartanLlama's answer using new and delete. Allocate memory first and then assign a value:
int *pointer = new int;
*pointer = 1; // OK
// delete when appropriate