I recently came across some very cool C++ tricks from some of the best coders which can help increase your code efficiency as well as make the code very neat , clean and easy to understand.I would be sharing some of these here.
1.Normally to find minimum among few elements we use something like this.
int a = min(x1,min(x2,min(x3,min(x4,x5))));
Instead of this we can use this.
int a = min({x2,x2,x3,x4,x5});
2.Using emplace_back in place of push_back
In C++ 11,emplace_back works just like push_back adding elements at the end of a vector. emplace_back is faster than push_back as push_back first creates a temporary variable and then adds it to the end of vector.
vector<int> v;
v.push_back(1); // Slower
v.emplace_back(2); //Faster
3.Using tuples
//Normally we use something like this
pair<int,pair<int,pair<char,int > > > p;
p=make_pair(1,make_pair(2,make_pair('a',3)));
// To access different elements we use something like this.
// TO access 1
int x=p.first;
// To access 2
int y=p.second.first;
//To access 'a'
char z=p.second.second.first;
//TO access 3
int s=p.second.second.second
// Instead of the above usage we can use tuples
tuple(int,int,char,int) t1=make_tuple(1,2,'a',3);
// TO access the ith element of a tuple we can use get<i> nameOfTuple
cout << get<0> t1 <<" "<<get<2>t1<<endl; // Prints 1 and 'a'
4.Lambda Functions
Yes we have Lambda functions in C++ as well.Lambda functions are functions which do not have a name.Normally when we have to write a comparator function for usage whenever we want to sort an array according to a certain rule.Sometimes these functions are very simple and we do not need to explicitly write a comparator function for that.This can be simply done using lambda function.
bool cmp(int a,int b){
return a>b;
}
vector<int> v;
v.emplace_back(1);
v.emplace_back(101);
v.emplace_back(5);
v.emplace_back(12);
v.emplace_back(-4);
// Now sorting
sort(v.begin(),v.end(),cmp);
// The above statement can be simple written without the comparator function
// using the lambda function
sort(v.begin(),v.end(),[](int a,int b){return a>b;});
// A lambda function is written like [](argument1,argument2,.....){//code}
5.Using Conditional Operators
Using conditional operators can make the code clean and efficient.
// Without conditional operators
if (a & 1) { // when a is odd
a=a*2;
}
else{
a=a+1;
}
// With conditional operators
a&1?a*=2:a+=1;
6. Bit Manipulation
// Conventional way to check ith bit set or not.
bool isSet(int num,int i){ // bit is counted from lsb to msb ..int this order 0th bit,1st bit...and so on
for(int j=0;j<i;j++){
num=num/2;
}
if(num&1)return true;
return false;
}
// Using shift operator
int t= num & (1<<i); // t is non zero (2^(i)) to be exact if ith bit is set else 0
// Setting ith bit
num|=(1<<i);
// flipping ith bit
num ^ = (1<<i); // ^ is the xor operator
// clearing the ith bit
num=num & ~(1<<i);
7.Using auto
Auto automatically determines the data type of the variable at run time and hence you need not to specify the data type of the variable.It also makes iterating over containers easy(code wise efficient).
auto a = 1; // a will become 'int'
auto b = 1LL; // b will become 'long long'
auto c = 1.0; // c will become 'double'
auto d = "variable"; // d will become 'string'
vector<int > v;
v.push_back(5);
v.push_back(10);
v.push_back(13);
// or instead you can write vector<int>v={5,10,13};
// Now to print the contents of v you can use
for (vector<int>::iterator it = v.begin(); it != v.end(); ++it)
cout << *it << ' ';
// or you can use auto keyword to ease your work
for(auto n:v)
cout<<n<<" ";
// Same goes for set , map and other data structures.
set<pair<int,int> >s;
s.insert({1,2}) // or you can use s.insert(make_pair(1,2))
s.insert({5,6}) // or s.insert(make_pair(5,6))
// or simply you can write set<pair<int,int> >s={ {1,2} , {5,6} }
// for printing the elements present in s
for (set<pair<int,int>>::iterator it = s.begin(); it != s.end(); ++it)
cout << (*it).first << ' '<<(*it).second<<"\n";
// or you can use auto to print its elements
for(auto x:s)
cout<<x.first<<" "<<x.second<<"\n";
\2. This is a completely wrong example of
emplace_back
usage, no one would use C++ if compilers couldn't optimizepush_back(int)
or evenpush_back(pair<int, int>)
.emplace_back
is used for two reasons: a) it's sometimes shorter, b) it's faster when the elements are containers themselves.emplace_back
forwards its arguments right to the constructor so you can use1, 2
and it'll be the same aspair<int, int>(1, 2)
(almost, because the latter also calls move constructor but oh well).Here's when
emplace_back
is slightly faster:\3. You mistyped the tuple syntax. It should be:
There are three points of interest:
a) It's
tuple<int, int, char, int>
, nottuple(int, int, char, int)
because these are template parameters, not function parameters.b)
get<I>(x)
is no magic, it's just a template functionget<I>
called with a single argumentx
. There is no special syntax here.c) No one uses
make_tuple
these days, you should try initializer lists:You could argue it's better to use
auto
andmake_tuple
like this, but personally I prefer making sure variable types are expected.In this statement:
auto d = "variable"; // d will become 'string'
d
will actually becomeconst char*
\4. The point of lambdas has never been having 'functions which do not have a name'. C++ lambdas simplify variable capture. Here's what it means:
Pretend that you want to sort an array, but instead of comparing values themselves, you compare
priority_of[value]
. In Python it's really simple:What about C++?
Hm, so what do you pass as a comparator? Maybe an external function?
Oops,
priority_of
is a local variable socompare
can't access it. Of course, you could make it global but that might become a problem if you use recursion, and copying is slow. You could also try pointers... but lambdas provide a simple solution:See this magic,
[&priority_of]
? This is called capture list.&
before variable name means that the list is passed by reference and is not copied. You can shorten the capture list like[&]
, but this means all variable references are stored so it may be a bit slower.Actually, using
[&]
will only capture the references to the variables you call inside the lambda, so it will be the same speed.Unfortunately I don't have any code at the moment but I remember that replacing
[&]
with[&var]
helped me once.Here's another idea. When you capture an integer by reference, this means a pointer to it is stored. When you access this variable later, it takes a bit more time than reading the integer directly. So it's better to capture primitives by value and other variables by reference, like this:
You don't need to use
auto
for range-based for loops. You can just use like this:The situation where
auto
is useful here is if you want to iterate using iterators:Also, since C++17, you can do this:
A bit offtopic but I think I should mention that this:
is identical to this:
except that the latter is a bit faster for non-primitives.
\5. Oh god, please don't write any such code ever!
This is not 'clean and efficient' code. It's horribly unreadable, especially if you don't use spaces, and a usual
if..else
construct is as fast as a conditional operator.Instead of this:
Use this:
Or, even better:
This is as fast as
a & 1
but (arguably) more readable and more obvious to other code readers.Here's the case when conditional operators actually simplify something. Pretend that you want to calculate 2D prefix sums. Here's how I usually do it:
Without conditional operators, the code would take more lines, and the
+
/+
/+
/-
structure wouldn't be as obvious.In addition: if-else is more convenient for debugging because you can see which branch is it going to.
Why don't you use a 1-indexed 2-D prefix sum, that eradicates the out of bounds issue with case i=0/j=0
I just want
pref
to have the same size and indexing asa
. Of course, you could makea
1-indexed too but that may require me to modify other algorithms, etc... so I just use 0-indexation everywhere and only fix prefix sums.[DELETED]
Conditional operator was not invented for statements, it's for expressions. You shouldn't use
a&1 ? a*=2 : ++a
, but you may usea = a&1 ? a*2 : a+1
. This way you explicitly state the intent: update a variable (a =
) depending (?
) on some condition (a&1
). (as a sidenote, I also hate it when people writeif(x) a++,b++;
instead ofif(x) { a++; b++; }
)You're right in the second example, code 1 is cleaner than code 2, except that I'd replace
(string)"IMPOSSIBLE"
with"IMPOSSIBLE"s
. Here you use?:
on expressions, not statements, and it works well here. (it'd be even better if C++ could infer the type ofn == -1 ? "IMPOSSIBLE" : n
expression asstd::variant<char*, int>
and was able to print it then, but sadly C++ is too strict)You are right.
U deserve a standing ovation
d will become a const char* (c string) NOT std::string, if you want it to become an std::string you need to use std::string's constructor: string(...) example:
But then it's just shorter to write
This blog contains too much fake news and should be removed, because is harmful for inexperienced coders.
The up- and downvote system is supposed to do that. Unfortunatly it does not allways work in the right direction :/
This comment section makes me feel like: Cunningham's Law states "the best way to get the right answer on the internet is not to ask a question; it's to post the wrong answer." xD
Still I really like these tricks and the comments were very helpful!