Dynamic allocation and functions

Consider the sippet below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
char *func(void)
{
    char *str = new char[3];
    str[0] = 'a';
    str[1] = 'b';
    str[2] = '\0';

    return str;
}

int main()
{
    cout << func() << endl;

    return 0;
}


Here I can get the str from func() but I cannot delete it, and if I delete str I wont be able to get str, how to solve this delema)?
Last edited on
The function dynamically allocated the array and returns the pointer to the caller.

Hence the caller is responsible for delete[]'ing the array when no longer needed, to avoid memory leaks!

Try something like:
1
2
3
4
5
6
7
8
int main()
{
    char *ptr = func();
    cout << ptr << endl;
    delete[] ptr;

    return 0;
}

...or with using std::unique_ptr smart pointers:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
std::unique_ptr<char[]> func(void)
{
    auto str = std::unique_ptr<char[]>(new char[3]); // <-- wrap array pointer in std::unique_ptr
    str[0] = 'a';
    str[1] = 'b';
    str[2] = '\0';
    return str; // <-- this implicitly "moves" the std::unique_ptr to the caller, thus transferring the ownership of the array from this function to the caller
}

int main()
{
    cout << func().get() << endl;  // <-- when the temporary std::unique_ptr object is destroyed, then the wrapped array is delete[]'ed automatically!
    return 0;
}
Last edited on
Just sayin', if you're going to using a unique_ptr<array>, you should really just consider using a string or vector. Of course, demonstrating its use for educational purposes like you did is fine, I just personally wouldn't use that in actual code.
Last edited on
You need to obtain the address returned by func() in a variable so that it can be used with delete[].

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>

auto func(void) {
	return new char[3] {"ab"};
}

int main() {
	const auto f { func() };

	std::cout << f << '\n';
	delete[] f;
}



However, a better way is to use 'smart' pointers then you don't need to bother about delete as this is done automatically when goes out of scope.

1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <memory>

auto func(void) {
	return std::unique_ptr<char[]> (new char[3] {"ab"});
}

int main() {
	std::cout << func() << '\n';
}

Just sayin', if you're going to using a unique_ptr<array>, you should really just consider using a string or vector. Of course, demonstrating its use for educational purposes like you did is fine, I just personally wouldn't use that in actual code.


Yeah - but still better than returning a raw pointer and needing delete []...
Smart pointer does the work ++

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>

std::unique_ptr<char[]> f(void)
{
    return std::unique_ptr<char[]>(new char[5]{ "test" });
}

int main()
{
    std::cout << f().get() << std::endl;
    return 0;
}
No leaks, no trouble...
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <string>

std::string func()
{
	return "ab";
}

int main()
{
	std::cout << func() << std::endl;
}
Last edited on
Small point - but stream extraction doesn't require .get() with a smart pointer to access the contents. In the above, f() works fine so no need for f().get()

No idea whether this leaks! (One of the problems with auto.)

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>

auto func()
{
	return "ab";
}

int main()
{
	std::cout << func() << '\n';
}
There is no dynamic allocation so no leaks.

The return type is simply deduced as const char*.
no - no leaks as no dynamic allocation.

However even if the return type of func() is known (const char*) this doesn't give us any info as to where pointer ownership resides. Do we need to delete[] it? In this case no as it wasn't obtained from a new and ownership isn't passed. But if the return address was obtained from a new then yes, we would need to delete[] it as ownership has been 'passed' but this can't be known from just the function return type.

If the ownership of the memory is to be passed, then a return type of std::unique_ptr makes this clear and the caller knows (and also doen't need to do anything about it as delete [] will be automatic when needed.
Last edited on
However even if the return type of func() is known (const char*) this doesn't give us any info as to where pointer ownership resides. Do we need to delete[] it?

That's why in Rust the ownership is explicit and is enforced/checked by the compiler (borrow checker):
https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html
https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html
Last edited on
I thought rust was 'to degenerate especially from inaction, lack of use, or passage of time'
Rust is a programming language that is supposed to be a "better C++" and replace C/C++ as The Sole Programming language eveh. At least according to Rust advocates and zealots.

I am not of them.

Rust is just the latest "shiny thing." Similar to Java, Rust is a nice idea next-step language that has IMO a niche applicability.

C/C++ are still dominant life forms for creating a wide variety of compiled applications. I don't see C/C++ being replaced any time soon.
Regarding Rust's borrow checker:

Both C++ and Rust support static checking of ownership.

C++'s approach to ownership is based on conventions, and is opt-in. To opt-in you make disciplined use of unique_ptr, value semantics, and RAII in your program.

Rust's approach to ownership is based on the definition of the type system, and is opt-out. To opt-out you put your code in an "unsafe block" which relaxes the type checker.

Rust does have some good ideas here. There's value in getting safety guarantees for free -- even though it's not going to be "free" all the time.

I expect it's already dogma to avoid their unsafe keyword.
Last edited on
Thank you all for contributing to this topic, I learn so much from you :)
Topic archived. No new replies allowed.