c pitfalls
-
NEVER call
top()/front()
when a (priority) queue is empty, it is an undefined behavior, and will not cause runtime error:#include <iostream> #include <queue> using namespace std; int main() { priority_queue<int> q; //cout << q.empty() << " " << q.top() << endl; // undefined, will destroy the priority queue and nothing is printed... q.push(1); cout << q.empty() << " " << q.top() << endl; // 0 1 q.pop(); cout << q.empty() << " " << q.top() << endl; // 1 1 (undefined behavior, seems still the last top element.) }
#include <iostream> #include <queue> using namespace std; int main() { queue<int> q; cout << q.empty() << " " << q.front() << endl; // 1 0 (undefined behavior, seems default to 0) q.push(1); cout << q.empty() << " " << q.front() << endl; // 0 1 q.pop(); cout << q.empty() << " " << q.front() << endl; // 1 0 (undefined behavior) }
-
unordered_map<pair<int, int>, int>
throws error likedeleted implicit constructor
:this is because there is no built in
hash
function forpair<>
. see here.Unfortunately there is no perfect solution:
- custom hash, like
p.first * MAX_SECOND + p.second
. - use
map<pair<int,int>, int>
.
- custom hash, like
-
std::map::operator[]
will initialize the value if key doesn't exist. (instead of throw an error likeat()
)cout << m[-1] << endl; // if not exist, will insert & initialize it ! (here int --> 0) cout << m.at(-1) << endl; // check if exist first, throw an error
-
string::operator[] & string::at
behaves similarly.string s = "a"; // [] won't check out of range! cout << "s[1] = " << s[1] << endl; // \0 cout << "s[2] = " << s[2] << endl; // undefined char cout << "s = " << s << endl; // a cout << "s.size() = " << s.size() << endl; // 1 // even if you modify it, it still won't throw an error. s[1] = 'b'; // dangerous! s[2] = 'c'; cout << "s[1] = " << s[1] << endl; // b cout << "s[2] = " << s[2] << endl; // c // but s is not changed. cout << "s = " << s << endl; // a cout << "s.size() = " << s.size() << endl; // 1 // at() checks out of range! cout << "s.at(1) = " << s.at(1) << endl; // error
-
%
modulo operator will return signed valuecout << -1 % 3 << endl; // -1 // to get a positive modulo (like % in python), we need: cout << (x % N + N) % N << endl;
.0f
forfloat 0
, not0f
-
0x80000000
default type isunsigned (int)
, while0x7fffffff
isint
.#include <iostream> #include <typeinfo> using namespace std; auto x = 0x80000000; cout << typeid(x).name() << " = " << x << endl; // j (unsigned) = 2147483648 int x = 0x80000000; cout << typeid(x).name() << " = " << x << endl; // i (int) = -2147483648 long long x = 0x80000000; // unsigned -> long long cout << typeid(x).name() << " = " << x << endl; // x (long long) = 2147483648 auto x = 0x7fffffff; cout << typeid(x).name() << " = " << x << endl; // i (int) = 2147483647
So if you want to get a number smaller than
INT_MIN
, you should do this:long long x = (long long)(int)0x80000000 - 1; // equals long long x = -2147483649;
-
str.erase
string s = "abc"; // str.erase(int pos, int len = npos); s.erase(1); // a s.erase(1, 1); // ac // str.erase(str::iterator it); s.erase(s.begin() + 1); // ac // str.erase(str::iterator begin, str::iterator end); s.erase(s.begin() + 1, s.end()); // a
-
though amazing, you can use
and
,or
in c++.// can be directly used in c++ // to use in c, need to include <iso646.h> && and &= and_eq & bitand | bitor ~ compl ! not != not_eq || or |= or_eq ^ xor ^= xor_eq { <% } %> [ <: ] :> # %: ## %:%:
- Structure binding of
tuple
cannot be used to assign value!// structure binding tuple<int, int> t = {1, 2}; auto [a, b] = t; // will CREATE and assign a, b to 1, 2 // however, if you already have a, b, you cannot assign value to them. int a = 0, b = 0; auto [a, b] = t; // error: conflicting declaration! // in certain cases, it will not give error but silently go wrong... int a = 0, b = 0; { // any new scope auto [a, b] = t; // a, b are local variables, not the a, b outside. } cout << a << " " << b << endl; // 0 0
- Sorting vector of pointers should use actual object's comparator:
struct Node { int val; Node(int val): val(val) {} // define the comparator bool operator<(const Node& other) const { return val < other.val; } }; int main() { vector<Node*> v; v.push_back(new Node(3)); v.push_back(new Node(1)); v.push_back(new Node(2)); // direct sort will compare **pointer values**, which is totally wrong! sort(v.begin(), v.end()); // use the actual object's comparatorff sort(v.begin(), v.end(), [](Node* a, Node* b) { return *a < *b; }); }
- For loop of container.size() will reflect the change of container size:
vector<int> v = {1, 2, 3}; for (int i = 0; i < v.size(); i++) { // at each iter, v.size() will be recalculated (different from python) cout << v[i] << " "; if (i < 3) v.push_back(i); // will change v.size() } // 1 2 3 0 1 2