To grant proper storage for what a pointer points to, is one of the most central problems in C++ code. Hence, a lot of effort has been done to eliminate the usage of raw pointers/new
/delete
as much as possible.
I struggled a bit to construct a simple example where a raw pointer really makes sense. So, assuming that in the following case, the raw pointer has been intentionally chosen to prevent unnecessary copying of constant data.
This constructed sample differs from OP's that in my case, struct A
is not responsible for life-time management of pointee. Instead, the pointer is used to refer to something which is life-time-managed outside of struct A
:
struct A {
const char *const name;
explicit A(const char *const name): name(name) { }
~A() = default;
A(const A&) = delete;
A& operator=(const A&) = delete;
const char* getName() const { return name; }
};
could be used e.g. this way:
A a("a");
So, struct A
is not responsible for life-time management of the passed pointer – no new
or delete
inside of struct A
.
However, this is also a weakness of the concept demonstrated in this counter example:
std::string name;
name = "a";
A a(name.c_str());
// Now, disaster begins
name = "bcdefghijklmnopqrstuvwxyz";
// as the previous storage in std::string name may be released
// but a is still alive.
struct A
trusts in that "outside" grants proper life-time of pointee. That could be over-enthusiastic as shown above. (My practical experience: Even well documented assumptions may be ignored by other programmers. Even with knowing the doc., this might be violated accidentally because of losing overview in too much code.)
Live Demo on coliru
Note: The output on coliru was:
a.getName(): ''
I expected a crash but, actually, this is Undefined Behavior – the former is as probable as the latter (as anything else, including "seems to work").
A possible fix:
struct A {
const std::string name;
explicit A(const char *const name): name(name) { }
~A() = default;
A(const A&) = delete;
A& operator=(const A&) = delete;
const char* getName() const { return name.c_str(); }
};
Now, struct A
makes a private copy of passed string in pointer where it manages itself the life-time of. This comes with the cost of some extra memory but the advantages are the lowered danger of wrong usage.
Instead of fiddling with new char[]
I just used std::string
, and all life-time issues are managed properly "under the hood".
To prevent raw pointers also, it could be modified to:
struct A {
const std::string name;
explicit A(const std::string &name): name(name) { }
~A() = default;
A(const A&) = delete;
A& operator=(const A&) = delete;
const std::string& getName() const { return name; }
};
which still can be used with:
A a("a"); // making an implicit conversion of (char[2])"a" to std::string