...
In this compliant solution, the dynamically allocated memory is not deallocated until it is no longer required:.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <new> struct S { void f(); }; void g() noexcept(false) { S *s = new S; // ... s->f(); delete s; } |
...
When possible, use automatic storage duration instead of dynamic storage duration. Since s
is not required to live beyond the scope of g()
, this compliant solution uses automatic storage duration to limit the lifetime of s
to the scope of g()
:.
Code Block | ||||
---|---|---|---|---|
| ||||
struct S { void f(); }; void g() { S s; // ... s.f(); } |
...
In the following noncompliant code example, the dynamically allocated memory managed by the buff
object is accessed after it has been implicitly deallocated by the object's destructor:.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <iostream> #include <memory> #include <cstring> int main(int argc, const char *argv[]) { const char *s = ""; if (argc > 1) { enum { BufferSize = 32 }; try { std::unique_ptr<char[]> buff(new char[BufferSize]); std::memset(buff.get(), 0, BufferSize); // ... s = std::strncpy(buff.get(), argv[1], BufferSize - 1); } catch (std::bad_alloc &) { // Handle error } } std::cout << s << std::endl; } |
...
In this compliant solution, the lifetime of the buff
object extends past the point at which the memory managed by the object is accessed:.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <iostream> #include <memory> #include <cstring> int main(int argc, const char *argv[]) { std::unique_ptr<char[]> buff; const char *s = ""; if (argc > 1) { enum { BufferSize = 32 }; try { buff.reset(new char[BufferSize]); std::memset(buff.get(), 0, BufferSize); // ... s = std::strncpy(buff.get(), argv[1], BufferSize - 1); } catch (std::bad_alloc &) { // Handle error } } std::cout << s << std::endl; } |
...
In this compliant solution, a variable with automatic storage duration of type std::string
is used in place of the std::unique_ptr<char[]>
, which reduces the complexity and improves the security of the solution:.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <iostream> #include <string> int main(int argc, const char *argv[]) { std::string str; if (argc > 1) { str = argv[1]; } std::cout << str << std::endl; } |
...
In this compliant solution, a local copy of the string returned by str_func()
is made to ensure that string str
will be valid when the call to display_string()
is made:.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <string> std::string str_func(); void display_string(const char *s); void f() { std::string str = str_func(); const char *cstr = str.c_str(); display_string(cstr); /* ok */ } |
...
The compliant solution depends on programmer intent. If the programmer intends to allocate a single unsigned char
object, the compliant solution is to use new
instead of a direct call to operator new()
, as this compliant solution demonstrates:.
Code Block | ||||
---|---|---|---|---|
| ||||
void f() noexcept(false) { unsigned char *ptr = new unsigned char; *ptr = 0; // ... delete ptr; } |
...