Common C++ Programming Errors and Memory Pitfalls
Classified in Computers
Written on in
English with a size of 6.93 KB
L-Values, R-Values, and Stack Variables
An l-value can be modified, while an r-value cannot be accessed again. Additionally, a stack variable is destroyed when it is popped from the stack.
Container Errors and Undefined Behavior
std::list Indexing Error
Code:
list<int> li;
li.push_front(5);
cout << li[1] << endl;Error: The subscript operator or function is not defined for this type. std::list does not have a [] operator because it does not support random access.
std::vector Out-of-Bounds Access
Code:
vector<string> v;
string h = "hello";
v[0] = h;
cout << v[0] << endl;Error: Indexing out of the bounds of the container. Since the vector is empty, this behavior is undefined.
Pointer and Reference Pitfalls
Uninitialized Pointer Arithmetic
Code:
int arr[5] = {1, 2, 3};
int i;
int *p = arr + i;Error: The variable i is never initialized, leading to illegal and unsafe pointer arithmetic.
Reference Assignment
Code:
int i = 15;
int j = 30;
int& k = j;
int* m = &i;
k = *m;Result: Both i and j become 15. Assigning *m to the reference k modifies the underlying variable j.
Const References
Code:
int i = 50;
const int& k = i;
i = 50;Result: Both i and k are 50. However, if you attempt to change the value directly through k (or if k was a pointer and you tried to change the value it points to), it will result in a compilation error.
Constant Pointers
Code:
int arr[5] = {1, 2, 3};
int* const p = arr + 2;
cout << *p;
++p;
cout << p;Error: p is a const pointer (int* const). You cannot change what p points to, so incrementing p (++p) causes a compilation error.
Pointer to Const Assignment
Code:
int i = 10;
const int j = 100;
int* p = &i;
*p = 50;
p = &j;
cout << p;Error: You cannot assign the address of a const variable (&j) to a non-const pointer (int* p). Doing so would allow modifying the constant value of j through the pointer, which is illegal.
Uninitialized Pointer Dereferencing
Code:
int i = 100;
int* p;
cout << *p;Error: The pointer p is not initialized. Dereferencing an uninitialized pointer is illegal and causes undefined behavior.
String Literal Assignment to char*
Code:
char *m = "midterm";Error: "midterm" is a string literal (type const char*), not a single char. Assigning a string literal directly to a non-const char* is invalid in modern C++ and can lead to compilation errors.
Pointer Arithmetic Evaluation
Code:
int arr[5] = {1, 2, 3, 4, 5};
int *p = arr;
int *m = arr + 2;
cout << *(m + *p);Result: Evaluates to 4. Since *p is 1, m + *p points to arr[3], which has a value of 4.
Vector Copy Behavior
Code:
int i = 10;
int j = 100;
int k = 1000;
vector<int> v;
v.push_back(i);
v.push_back(j);
v.push_back(k);
v[0] = 11;
v[1] = 111;
v[2] = 1111;
cout << "i:" << i << " j:" << j << " k:" << k;Result: Outputs i:10 j:100 k:1000. Modifying the elements inside the vector does not affect the original variables because push_back stores copies of the values.
Exception Handling in C++
Uncaught Exceptions
Code:
void func() {
throw "exception";
}
int main(int argc, char *argv[]) {
try {
func();
} catch(std::exception &e) {
cout << "caught exception" << endl;
}
catch (int &i) {
cout << "caught int" << endl;
}
catch (string &s) {
cout << "caught string" << endl;
}
return 0;
}Error: Not all exceptions are caught. Throwing a string literal (const char*) will not be caught by std::exception, int, or std::string. You need a catch(...) block to catch any unhandled exception types.
Catch-All Exception Block
Code:
void func() {
throw -1;
}
int main(int argc, char *argv[]) {
try {
func();
} catch(std::exception &e) {
cout << "caught exception" << endl;
} catch(unsigned int &i) {
cout << "caught uint" << endl;
} catch(string &s) {
cout << "caught string" << endl;
} catch(...) {
cout << "caught unknown" << endl;
}
return 0;
}Result: Outputs caught unknown. The thrown value is a signed int (-1), which does not match unsigned int, std::string, or std::exception, so it falls back to the catch-all catch(...) block.
Structs and Function Overloading
Missing Operator Overloading
Code:
struct Foo {
int x;
int y;
Foo(int i, int j) : x(i), y(j) {}
};
int main(int argc, char* argv[]) {
Foo F1(1, 2);
Foo F2(2, 2);
if (F1 != F2) {
cout << "no match" << endl;
} else {
cout << "match" << endl;
}
return 0;
}Error: The inequality operator (!=) is undefined for Foo because no comparison operators are defined inside the struct. The compiler does not know how to compare the two objects.
Ambiguous Function Overloading
Code:
int sum(vector<int> &v);
int sum(vector<int> &v, int offset = 0);
int main(int argc, char* argv[]) {
vector<int> v;
v.push_back(10);
cout << sum(v);
return 0;
}Error: This causes a compilation error due to ambiguity. The call sum(v) can refer to both functions because the second function has a default argument for offset, making both signatures valid candidates.
Incomplete Class Definition
class Bar {
// Incomplete class definition
};