Skip to content

Instantly share code, notes, and snippets.

@co89757
Last active April 3, 2016 05:56
Show Gist options
  • Save co89757/4f0b6ac58de5c29190a1 to your computer and use it in GitHub Desktop.
Save co89757/4f0b6ac58de5c29190a1 to your computer and use it in GitHub Desktop.
a scrap note for programming learning

C++ Notes

C++ 11 features

* bind function
Mixing bound and call arguments with placeholders
  • Example
#include <functional>
using namespace std;
using namespace std::placeholders; // needed for _1, _2, etc
int sum3(int a, int b, int c)
{
int sum = a+b+c;
return sum;
}
int result = bind(sum3, _1, _2, 4) (5,6) ; // --> 5+6+4 = 15 
Using bind with Class Objects

We can call functions that modify the supplied object, but we need to note if it is a copied one or the original reference.

  • examples
bind(update_Thing, t1)() ;  // modify a copy of t1 
bind(update_Thing, ref(t1)) (); // modify original t1
bind(update_Thing, _1) (t1) ; // modify original t1

to use bind with mem-functions, just use & to specify a pointer-to-mem_fn , ** also ensure the Thing object is supplied as the first arg to explicitly fill in the place of this.

  • examples
bind(&Thing::print, t1)();
bind(&Thing::print, _1)(t1);
bind(&Thing::write, _1, ref(cout))(t1);
bind(&Thing::print1arg, _1, _2)(t1, int2);
bind(&Thing::print2arg, _2, _1, _3)(int3, t1, int2);
Using bind with map Container
  • example Suppose we start to write a for_each loop that we want to apply the print member function for each Thing in the container:
for_each(obj_map.begin(), obj_map.end(),
  bind(&Thing::print, what goes in here?) );

bind is extremely smart about making use of a function pointer, and can understand a pointer-to- member-function. In fact, it can make sense of something that isn't a function pointer in the usual sense of the word, but is the rarely-used pointer-to-member-variable. If you supply a pointer-to-member-variable, bind will construct a function object that simply returns the value of that member variable for a supplied object.

  • example
for_each(obj_map.begin(), obj_map.end(),
 bind(&Thing::print,
   bind(&Omap_t::value_type::second, _1)) );

_BEWARE! bind vs lambda

lambda cannot handle move-only types such as unique_ptr, so you can't use unique ptr inside a lambda body. refer to this when not to use lambda

A handy short cut for mem_fn when no binding is needed

C++11 also includes a function template called mem_fn. Like bind , mem_fn creates and returns a function object that can be used with function call syntax to call the wrapped function, both for a supplied object and a pointer to an object.

mem_fn(&Thing::print) (t1);
mem_fn(&Thing::print) (t1_ptr);
for_each(obj_list.begin(), obj_list.end(), mem_fn(&Thing::print));
  • override, final, delete for member functions

Abstract Base Class

Abstract classes cannot be used for:

  • Variables or member data
  • Argument types
  • Function return types
  • Types of explicit conversions Another restriction is that if the constructor for an abstract class calls a pure virtual function, either directly or indirectly, the result is undefined. However, constructors and destructors for abstract classes can call other member functions. Pure virtual functions can be defined for abstract classes, but they can be called directly only by using the syntax: abstract-class-name :: function-name( )

This helps when designing class hierarchies whose base class(es) include pure virtual destructors, because base class destructors are always called in the process of destroying an object. Consider the following example:

Diamond Problem [multi-inheritance in c++]

radio::radio ()
    : storable( 10 ) // some value that storable needs 
    , transmitter()
    , receiver()
{}

One thing to be aware of is that if either transmitter or receiver attempted to invoke the storable constructor in their initialization lists, that call will be completely skipped when constructing a radio object! Be careful, as this could cause a subtle bug!

By the way, the constructors for virtual base classes are always called before the constructors for non-virtual base classs. This ensures that a class inheriting from a virtual base class can be sure the virtual base class is safe to use inside the inheriting class's constructor.

The destructor order in a class hierarchy with a virtual base class follows the same rules as the rest of C++: the destructors run in the opposite order of the constructors. In other words, the virtual base class will be the last object destroyed, because it is the first object that is fully constructed.

Multiple inheritance smells, which means that usually, it was done for bad reasons, and it will blow back in the face of the maintainer.

###Summary

Consider composition of features, instead of inheritance Be wary of the Diamond of Dread Consider inheritance of multiple interfaces instead of objects Sometimes, Multiple Inheritance is the right thing. If it is, then use it. Be prepared to defend your multiple-inherited architecture in code reviews ####1. Perhaps composition?

This is true for inheritance, and so, it's even more true for multiple inheritance.

Does your object really needs from another? A Car do not need to inherit from an Engine to work, nor from a Wheel. A Car has an Engine and four Wheel.

If you use multiple inheritance to resolve this problem instead of composition, then you did something wrong.

####2. The Diamond of Dread

Usually, you have a class A, and then B and C both inherit from A. And don't ask me why, someone then decides that D must inherit both from B and C.

I encountered this kind of problem twice in 8 eights years, and it is amusing to see because of:

How much a mistake it was from the beginning (In both cases, D should not have inherited from both B anc C), because this was bad architecture (in fact, C should not have existed at all...) How much maintainers were paying for that, because in C++, the parent class A was present twice in its grandchild class D, and thus, updating one parent field A::field meant either updating them twice (through B::field and C::field), or have something goes silently wrong and crash, later (new a pointer in B::field, and delete C::field...) Using the keyword virtual in C++ void the double layout described above, but anyway, you're probably doing something wrong...

In Object hierarchy, you should keep the hiearchy as a Tree (a node has ONE parent), not as a graph.

####3. Interfaces

Multiple inheritance of zero or one concrete classe, and zero or more interfaces is usually Ok, because you won't encounter the Diamond of Dread described above. In fact, this is how things are done in Java.

Usually, what you mean when C inherits from A and B is that users can use C as if it was a A, and/or as if it was a B.

In C++, an interface is an abstract class which has:

all its method declared pure virtual (suffixed by = 0) no member variables The Multiple inheritance of zero to one real object, and zero or more interfaces is not considered "smelly" (at least, not as much)

####4. Do you really need Multiple Inheritance?

Sometimes, yes.

Usually, your C class is inheriting from A and B, and A and B are two unrelated objects (i.e. not in the same hierarchy, nothing in common, different concepts, etc.).

For example, you could have a system of Nodes with X,Y,Z coordinates, able to do a lot of geometric calculations (perhaps a point, part of geometric objects) and each Node is an Automated Agent, able to communicate with other agents.

Perhaps you already have access to two libraries, each with its own namespace (another reason to use namespaces... But you use namespaces, don't you?), one being "geo" and the other bing "ai"

So you have your own "own::Node" derive both from "ai::Agent" and "geo::Point".

This is the moment when you should ask yourself if you should not use composition instead. If "own::Node" is really really both a "ai::Agent" and a "geo::Point", then composition would not do.

Then you'll need multiple inheritance, having your "own::Node" communicate with other agents according to their position in a 3D space.

(You'll note that ai::Agent and geo::Point are completely, totally, fully UNRELATED... This is what reduces drastically the danger of multiple inheritance)

####5. So, should I do Multiple Inheritance?

Most of the time, no. MI is not the right tool, even if it seems it will work.

But sometimes, yes. And at that time, nothing will work better than MI, and you won't have a Diamond of Dread, and your object is really both its parent.

But because MI is smelly, be prepared to defend your architecture in code reviews (and defending it is a good thing, because if you're not able to defend it, then you should not do it). [virtual method table wiki] (http://en.wikipedia.org/wiki/Virtual_method_table)

C++11 lambda expressions

Syntax

Examples

use lambda in class methods

You can use lambda expressions in the body of a method. The lambda expression can access any method or data member that the enclosing method can access. You can explicitly or implicitly capture the this pointer to provide access to methods and data members of the enclosing class.

void ApplyScale(const vector<int>& v) const
{
   for_each(v.begin(), v.end(), 
      [this](int n) { cout << n * _scale << endl; });
}

Cautions on use of STL map

Don’t change the key of map element by iterator, because it may break the integrity of map internal data structure (see below). There is one important difference between map::find() and map::operator []. While map::find() will never change the contents of map, operator [] will create an element if it does not exist. In some cases this could be very convenient, but it's definitly a bad idea to use operator [] many times in a loop, when you do not want to add new elements. That’s why operator [] may not be used if map is passed as a const reference parameter to some function.

 void f(const map<string, int>& M) { 
      if(M["the meaning"] == 42) { // Error! Cannot use [] on const map objects! 
      } 
      if(M.find("the meaning") != M.end() && M.find("the meaning")->second == 42) { // Correct 
           cout << "Don't Panic!" << endl; 
      } 
 } 

Advanced tutorial on STL tricks

####Creating Vector from Map As you already know, map actually contains pairs of element. So you can write it in like this:

 map<string, int> M; 
 // ... 
 vector< pair<string, int> > V(all(M)); // remember all(c) stands for 
 (c).begin(),(c).end() 

Now vector will contain the same elements as map. Of course, vector will be sorted, as is map. This feature may be useful if you are not planning to change elements in map any more but want to use indices of elements in a way that is impossible in map.

Split/Join operations on string as in Python

vector<string> ssplit(string s, char delim ){
   istringstream iss(s);
   vector<string> result;
   string token;
   while(getline(iss,token, delim)){
     result.push_back(token);

   }   
 return result;

}

string join(vector<string> vs, char glue){
    string result;
    for_each(begin(vs), end(vs), [glue,&result](string s){result.append(s).append(1,glue); }  );
    result.resize(result.size()-1);
    return result;

}

##TIPS and TRICKS with scanf

Assume we have: char a[100];

####To read a string:

scanf("%[^\n]\n", a);

// it means read until you meet '\n', then trash that '\n'

####To read till a coma:

scanf("%[^,]", a);
// this one doesn't trash the coma


scanf("%[^,],",a);
// this one trashes the coma

If you want to skip some input, use * sign after %. For example you want to read last name from "John Smith" :

scanf("%s %s", temp, last_name);
// typical answer, using 1 temporary variable

scanf("%s", last_name);
scanf("%s", last_name);
// another answer, only use 1 variable, but calls scanf twice

scanf("%*s %s", last);
// best answer, because you don't need extra temporary variable nor calling scanf twice
tip: using std::tuple and std::tie() for lexicographical comparison.
struct Student{
string name;
int ID;
int GPA;

bool operator<(const Student & other){
return tie(name,ID,GPA) < tie(other.name, other.ID, other.GPA);
}

};

### Pimpl idiom notes

__BEWARE__ ! The class that uses PIMPL idiom MUST have a destructor implemented. Else, you will have incomplete type error for the unique_ptr to impl. 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment