Using raw pointers
Most often leads to the problem of not following the rule of three/five/zero. Also easy to skip the initialization step and start accessing private fields while the object is still nullptr
.
Skipping virtual destructor in base class
class Base {
public:
Base() { }
~Base() { }
};
class Derived : public Base {
public:
Derived() { }
~Derived() { }
};
int main() {
Base* b = new Derived();
delete b; // only base class destructor called
return 0;
}
The fix is easy. Add the virtual
keyword to the destructor of the base class.
virtual ~Base() { }
Now when we call delete
on b
, both the destructor for Base
and the destructor for Derived
are called,
Return a reference from method
The problem with returning a reference from a method is that the reference may become invalid or even refer to an object that no longer exists
class Example {
public:
Example(int value) : m_value(value) { }
int& getValue() { return m_value; }
private:
int m_value;
};
int main() {
int init = 0
int& value = init;
{
Example ex(42);
value = ex.getValue();
cout << value << endl; // prints 42
}
// ex goes out of scope, m_value is destroyed
cout << value << endl; // undefined behavior!
return 0;
}
Pointer parameter in a function
If you pass a pointer to a function as a parameter then you cannot assign it to another pointer within the function.
void assignPointer(int* ptr) {
int* newPtr = new int(42); // dynamically allocate memory for new integer
ptr = newPtr; // assign new pointer to function parameter
}
int main() {
int* ptr = nullptr;
assignPointer(ptr); // pass pointer to function
// ptr still points to nullptr, memory leak occurs
delete ptr; // undefined behavior, as ptr was never assigned a valid address
return 0;
}
+1 for null terminated strings
The null character \0'
is used to indicate the end of the string. When we allocate memory for a string, we must make sure to allocate enough space for the string and one extra byte for the null character.
#include <cstring> // for std::memcpy and std::strlen
#include <iostream> // for std::cout and std::endl
int main()
{
const char* str = "Hello, world!";
const std::size_t len = std::strlen(str);
char* buf = new char[len]; // error
std::memcpy(buf, str, len); // missing the null character
std::cout << "Copied string: " << buf << std::endl; // length will extend to the first 0 found in memory
delete[] buf;
return 0;
}