mirror of
https://github.com/libretro/cpp-cheat.git
synced 2025-04-14 01:00:25 +00:00
9717 lines
289 KiB
C++
9717 lines
289 KiB
C++
/*
|
|
C++ cheatsheat.
|
|
|
|
Features which are identical to C will not be described.
|
|
*/
|
|
|
|
/*
|
|
# Headers
|
|
|
|
C++ stdlib headers that are not C stdlib headers don't have the `.h` extension,
|
|
and therefore are not included with the `.h` extension.
|
|
|
|
Pre-standardized versions of C++ by Stroustrup used the `.h` extension, for example `iostream.h`,
|
|
but this has been deprecated: <http://stackoverflow.com/questions/214230/iostream-vs-iostream-h-vs-iostream-h>
|
|
It may still exits on certain systems, but never rely on it.
|
|
|
|
When writting new libs, you can use either `.h` or `.hpp` as extensions,
|
|
where `.hpp` indicates that the header is C++ specific, and not pure C.
|
|
|
|
# C headers
|
|
|
|
The standard C++ library provides a `cNAME` version to every `NAME.h` for every C header.
|
|
E.g.: `math.h` vs `cmath`.
|
|
|
|
The difference is the following:
|
|
|
|
- cX puts things in std:: namespace. *always* use the CNAME version on new code,
|
|
since this reduces the probability of a name conflicts, and is the standard c++ way of doing things.
|
|
|
|
Macro expansion happens *before* namespaces are even compiled,
|
|
so you still refer to macros like `EXIT_SUCCESS` and `assert` as in C,
|
|
and *not* as `std::EXIT_SUCCESS`.
|
|
|
|
- `X.h` puts *all* in the global namespace, it is exactly the same as the c headers.
|
|
*never* use it in new code.
|
|
|
|
Those headers exist only for backwards compatibility.
|
|
|
|
Avoid using C headers and functionality altogether if that functionality has an equivalent C++ version,
|
|
since the C++ version will play more nicely with new language features and libraries.
|
|
|
|
# Linux specifics
|
|
|
|
The main c++ lib on linux is the GNU Standard C++ Library.
|
|
|
|
Shared object name: `libstdc++.so`.
|
|
|
|
Website: <http://gcc.gnu.org/libstdc++/>
|
|
|
|
Get source code: seems to be on the same tree as gcc?
|
|
|
|
git clone git://gcc.gnu.org/git/gcc.git
|
|
|
|
- the so is usually located at
|
|
|
|
/usr/lib/i386-linux-gnu/libstdc++.so.X
|
|
|
|
If it is not there then
|
|
|
|
locate libstdc++
|
|
|
|
- std headers are usually located at
|
|
|
|
/usr/include/c++/4.X/`.
|
|
|
|
If not, try:
|
|
|
|
locate /iostream
|
|
|
|
- the Ubuntu package is called `libstdc++6.X`. `dpkg -l | grep libstd`
|
|
|
|
With `g++` the C++ standard library is linked against automatically.
|
|
This does not happen when compiling with `gcc`, and is one of the many reasons why you should use `g++`
|
|
whenever compiling C++ instead of `gcc`.
|
|
*/
|
|
|
|
#include <array> // array
|
|
#include <algorithm> // copy, erase, lower_bound, remove_if, swap, transform
|
|
#include <chrono> // nanoseconds
|
|
#include <exception> // bad_alloc, bad_cast, bad_exception, bad_typeid, exception, ios_base::failure
|
|
#include <fstream> // fstream, ifstream, ofstream
|
|
#include <functional> // bind2nd
|
|
#include <iostream> // cout, endl
|
|
#include <iterator> // advance, input_iterator_tag, iterator, iterator_traits, next
|
|
#include <list> // forward_list, list
|
|
#include <limits> //
|
|
#include <map> // map, multimap
|
|
#include <memory> // shared_ptr
|
|
#include <mutex> //
|
|
#include <new> //
|
|
#include <numeric> // partial sums, differences on std::vectors of numbers
|
|
#include <regex> //
|
|
#include <set> // multiset, set
|
|
#include <string> // getline, string
|
|
#include <sstream> // stringstream
|
|
#include <thread> //
|
|
#include <typeinfo> // typeid, bad_typeid, bad_typecast
|
|
#include <typeindex> // type_index
|
|
#include <tuple> // tuple
|
|
#include <unordered_map> // unordered_map, unordered_multimap
|
|
#include <utility> // forward, get, pair, size_t, type_info
|
|
#include <vector>
|
|
#include <valarray>
|
|
|
|
// C headers.
|
|
#include <cassert>
|
|
#include <cmath>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
|
|
// Keeps a list of functions that called it for testing purposes.
|
|
static std::vector<std::string> callStack;
|
|
void printCallStack() {
|
|
std::cout << "callStack:" << std::endl;
|
|
for (auto& s : callStack)
|
|
std::cout << s << std::endl;
|
|
std::cout << "END callStack" << std::endl;
|
|
}
|
|
|
|
// Exception
|
|
|
|
void exception_func_int() {
|
|
throw 1;
|
|
}
|
|
|
|
class myexception: public std::exception {
|
|
virtual const char* what() const throw() {
|
|
return "myexception::what()";
|
|
}
|
|
};
|
|
|
|
// Exception specifications
|
|
|
|
// All exceptions are catchable (default):
|
|
void exception_func_all() { throw 0; }
|
|
|
|
// Only int exceptions are catchable
|
|
void exception_func_int_only(bool throw_int) throw (int) {
|
|
if (throw_int)
|
|
throw 1;
|
|
else
|
|
throw 'c';
|
|
}
|
|
|
|
// Only int and exception or derived excpetions are catchable:
|
|
void exception_func_int_exception_only(int which) throw (int, std::exception) {
|
|
switch (which) {
|
|
case 0: throw 0; break;
|
|
case 1: throw myexception(); break;
|
|
default: throw 'c'; break;
|
|
}
|
|
}
|
|
|
|
// No exceptions are catchable
|
|
void exception_func_none() throw() {throw 1;}
|
|
|
|
void exception_func_none_wrapper() {
|
|
exception_func_none();
|
|
}
|
|
|
|
/**
|
|
The destructor of this class throws an exception!!!
|
|
*/
|
|
class ExceptionDestructor {
|
|
public:
|
|
~ExceptionDestructor() { throw std::exception(); }
|
|
};
|
|
|
|
void ExceptionDestructorCaller() {
|
|
ExceptionDestructor e;
|
|
}
|
|
|
|
// #class
|
|
//{
|
|
class Empty {};
|
|
|
|
/**
|
|
This class has a compiler supplied default constructor.
|
|
*/
|
|
class ImplicitDefaultCtor {
|
|
public:
|
|
int i;
|
|
std::string s;
|
|
};
|
|
|
|
/**
|
|
This class has no default constructor since another constructor was defined.
|
|
*/
|
|
class NoDefaultCtor {
|
|
public:
|
|
NoDefaultCtor(int i) : i(i) {}
|
|
int i;
|
|
};
|
|
|
|
/**
|
|
This class defines a default constructor since it will also provide a non default one.
|
|
*/
|
|
class ExplicitDefaultCtor {
|
|
public:
|
|
int i;
|
|
ExplicitDefaultCtor(){}
|
|
ExplicitDefaultCtor(int i) : i(i){}
|
|
};
|
|
|
|
/**
|
|
This class uses its default copy constructor and assign operator.
|
|
*/
|
|
class DefaultCopyAssignCtor {
|
|
public:
|
|
int i;
|
|
DefaultCopyAssignCtor() : i(0) {}
|
|
DefaultCopyAssignCtor(int i) : i(i) {}
|
|
};
|
|
|
|
/**
|
|
This politically incorrect clas does not implement the equality == operator.
|
|
*/
|
|
class NoEquality {
|
|
public:
|
|
NoEquality() : i(0) {}
|
|
int i;
|
|
};
|
|
|
|
#if __cplusplus >= 201103L
|
|
class CtorFromCtor {
|
|
|
|
public:
|
|
|
|
std::vector<int> v;
|
|
|
|
/**
|
|
This constructor does the default which is calling the parent's default constrctor before its own.
|
|
|
|
An error would be generated if the parent class has no defalt constructor.
|
|
*/
|
|
CtorFromCtor(int i) : v(1,i) {}
|
|
|
|
/**
|
|
This constructor calls another constructor with arguments before running its own.
|
|
*/
|
|
CtorFromCtor(int i, int j) : CtorFromCtor(i) {
|
|
v.push_back(j);
|
|
}
|
|
};
|
|
#endif
|
|
|
|
/**
|
|
Simple class for tests on constructor destructor order.
|
|
|
|
This class has no members which are objects and no base classes.
|
|
*/
|
|
class NoBaseNoMember {
|
|
public:
|
|
|
|
int i;
|
|
|
|
/// Default constructor
|
|
NoBaseNoMember() : i(0) {
|
|
callStack.push_back("NoBaseNoMember::NoBaseNoMember()");
|
|
}
|
|
|
|
/// Copy constructor
|
|
NoBaseNoMember(const NoBaseNoMember& other) : i(other.i) {
|
|
callStack.push_back("NoBaseNoMember::NoBaseNoMember(NoBaseNoMember)");
|
|
}
|
|
|
|
NoBaseNoMember(int i) : i(i) {callStack.push_back("NoBaseNoMember::NoBaseNoMember(int)");}
|
|
|
|
/// Assign
|
|
NoBaseNoMember& operator= (const NoBaseNoMember& rhs) {
|
|
this->i = rhs.i;
|
|
callStack.push_back("NoBaseNoMember::operator=");
|
|
return *this;
|
|
}
|
|
|
|
/// Destructor
|
|
~NoBaseNoMember(){callStack.push_back("NoBaseNoMember::~NoBaseNoMember()");}
|
|
|
|
void method(){callStack.push_back("NoBaseNoMember::method()");}
|
|
|
|
static NoBaseNoMember create() {
|
|
return NoBaseNoMember();
|
|
}
|
|
|
|
static NoBaseNoMember createNrvo() {
|
|
NoBaseNoMember c;
|
|
return c;
|
|
}
|
|
|
|
/// It would be hard or impossible to do RVO for this function.
|
|
static NoBaseNoMember createNrvoHard(bool b = false) {
|
|
//2 int constructors
|
|
NoBaseNoMember cf = NoBaseNoMember(0);
|
|
NoBaseNoMember ct = NoBaseNoMember(1);
|
|
return b ? ct : cf;
|
|
//2 int destructors
|
|
}
|
|
|
|
static void temporaryReference(NoBaseNoMember& temp) {
|
|
temp.i = 0;
|
|
}
|
|
|
|
static void temporaryReferenceConst(const NoBaseNoMember& temp) {}
|
|
};
|
|
|
|
class ExplicitCtor {
|
|
public:
|
|
int i;
|
|
explicit ExplicitCtor(int i) : i(i) {}
|
|
|
|
explicit ExplicitCtor(int i, int j) : i(i + j) {}
|
|
// TODO this makes no sense right, since it is not a ctor that takes a single arg?
|
|
// why does it compile without warning
|
|
|
|
// ERROR: only for constructors.
|
|
//explicit void method(){}
|
|
};
|
|
|
|
class NoBaseNoMember0 {
|
|
public:
|
|
NoBaseNoMember0(){callStack.push_back("NoBaseNoMember0::NoBaseNoMember0()");}
|
|
~NoBaseNoMember0(){callStack.push_back("NoBaseNoMember0::~NoBaseNoMember0()");}
|
|
void method(){callStack.push_back("NoBaseNoMember0::method()");}
|
|
};
|
|
|
|
class NoBaseNoMember1 {
|
|
public:
|
|
NoBaseNoMember1(){callStack.push_back("NoBaseNoMember1::NoBaseNoMember1()");}
|
|
~NoBaseNoMember1(){callStack.push_back("NoBaseNoMember1::~NoBaseNoMember1()");}
|
|
void method(){callStack.push_back("NoBaseNoMember1::method()");}
|
|
};
|
|
|
|
|
|
#if __cplusplus >= 201103L
|
|
|
|
/**
|
|
This class exemplifies the `= default` syntax.
|
|
*/
|
|
class DefaultKeyword {
|
|
public:
|
|
|
|
/**
|
|
This is an explicitly defaulted constructor.
|
|
*/
|
|
DefaultKeyword() = default;
|
|
|
|
/**
|
|
This is an explicitly defaulted copy constructor.
|
|
*/
|
|
DefaultKeyword(const DefaultKeyword&) = default;
|
|
|
|
/**
|
|
This is an explicitly defaulted assignment operator.
|
|
*/
|
|
DefaultKeyword & operator=(const DefaultKeyword&) = default;
|
|
|
|
~DefaultKeyword() = default;
|
|
|
|
// ERROR: Not possible because the default constructor must take no arguments.
|
|
//DefaultKeyword(int i) = default;
|
|
|
|
// With the default keyword it is possible to have other
|
|
// constructors besides the Implicitly defined constructor.
|
|
DefaultKeyword(int i, std::string s) : i(i), s(s) {}
|
|
|
|
|
|
/**
|
|
ERROR: Cannot default anything other than:
|
|
|
|
- constructors
|
|
- destructors
|
|
- copy
|
|
- assignment
|
|
*/
|
|
//void f() = default;
|
|
|
|
int i;
|
|
std::string s;
|
|
};
|
|
|
|
/**
|
|
This class exemplifies the `= delete` syntax.
|
|
*/
|
|
class DeleteKeyword {
|
|
public:
|
|
DeleteKeyword() = delete;
|
|
DeleteKeyword(int i) : i(i) {}
|
|
DeleteKeyword(const DeleteKeyword&) = delete;
|
|
DeleteKeyword & operator=(const DeleteKeyword&) = delete;
|
|
|
|
/**
|
|
With this, the code would compile, but it would not be possible
|
|
to create any instances of this class, since at some point the destructor
|
|
would have to be called!
|
|
*/
|
|
//~DeleteKeyword() = delete;
|
|
|
|
/* It is possible to delete any function. */
|
|
void f() = delete;
|
|
int i;
|
|
};
|
|
|
|
#endif
|
|
|
|
/**
|
|
This class has an implicit default constructor.
|
|
*/
|
|
class UniformInitializationImplicitCtor {
|
|
public:
|
|
int i;
|
|
int j;
|
|
};
|
|
|
|
/**
|
|
This class has an explicit default constructor,
|
|
and no constructor that takes 2 ints.
|
|
*/
|
|
class UniformInitializationExplicitCtor {
|
|
public:
|
|
int i;
|
|
int j;
|
|
UniformInitializationExplicitCtor() : i(0), j(0) {}
|
|
};
|
|
|
|
/**
|
|
This class has a constructor that takes 2 ints.
|
|
*/
|
|
class UniformInitializationCtor2 {
|
|
public:
|
|
int i;
|
|
int j;
|
|
UniformInitializationCtor2(int i, int j) : i(i), j(j+1) {}
|
|
bool operator==(const UniformInitializationCtor2& other) {return this->i == other.i && this->j == other.j;}
|
|
};
|
|
|
|
int UniformInitializationCtor2Func(UniformInitializationCtor2 o){
|
|
return o.i + o.j;
|
|
}
|
|
|
|
class UniformInitializationList {
|
|
public:
|
|
int i;
|
|
int j;
|
|
UniformInitializationList(int i, int j) : i(i), j(j+1) {}
|
|
UniformInitializationList(std::initializer_list<int> list){
|
|
i = *(list.begin());
|
|
j = *(list.begin() + 1);
|
|
}
|
|
};
|
|
|
|
#if __cplusplus >= 201103L
|
|
|
|
/**
|
|
This class has an `Initializer_list` constructor.
|
|
*/
|
|
class InitializerListCtor {
|
|
public:
|
|
|
|
std::vector<int> v;
|
|
|
|
InitializerListCtor(std::initializer_list<int> list) {
|
|
for (auto& i : list)
|
|
v.push_back(i);
|
|
}
|
|
|
|
InitializerListCtor(int before, std::initializer_list<int> list, int after) {
|
|
v.push_back(before + 1);
|
|
for (auto& i : list)
|
|
v.push_back(i);
|
|
v.push_back(after - 1);
|
|
}
|
|
};
|
|
|
|
#endif
|
|
|
|
class MemberConstructorTest {
|
|
public:
|
|
NoBaseNoMember0 member0;
|
|
NoBaseNoMember1 member1;
|
|
MemberConstructorTest(){callStack.push_back("MemberConstructorTest::MemberConstructorTest()");}
|
|
~MemberConstructorTest(){callStack.push_back("MemberConstructorTest::~MemberConstructorTest()");}
|
|
void method(){callStack.push_back("MemberConstructorTest::method()");}
|
|
};
|
|
|
|
class Member {
|
|
public:
|
|
Member(){callStack.push_back("Member::Member()");}
|
|
Member(int i){callStack.push_back("Member::Member(int)");}
|
|
~Member(){callStack.push_back("Member::~Member()");}
|
|
|
|
void method() {callStack.push_back("Member::method()");}
|
|
|
|
int i;
|
|
};
|
|
|
|
class Nested {
|
|
public:
|
|
Nested() { callStack.push_back("Nested::Nested()"); }
|
|
};
|
|
|
|
/*
|
|
# this
|
|
|
|
Magic value that points to the current object.
|
|
|
|
It is implemented by the compiler by passing `this` as the first argument
|
|
of every non-static function of the class.
|
|
|
|
This is noticeable when doing operator overload:
|
|
*/
|
|
|
|
class Base {
|
|
public:
|
|
|
|
/// Best to put typedefs on top of class so def will go for entire class.
|
|
typedef int NESTED_INT;
|
|
|
|
Base() : i(0), j(1) {
|
|
callStack.push_back("Base::Base()");
|
|
|
|
// BAD: same as list init, except if i is an object
|
|
// to keep uniform style, always use list init
|
|
//this->i=0;
|
|
//this->j=1;
|
|
|
|
// ERROR: ic is const. must be initialized in list initialization.
|
|
//ic=0;
|
|
|
|
// BAD: compiles but infinite loop!
|
|
//Base b;
|
|
}
|
|
/*
|
|
# Initialization list
|
|
|
|
Initialization lists have 4 main uses:
|
|
|
|
1) avoid calling member object constructor and copy separately
|
|
2) initializing base classes with non default constructors
|
|
3) initializing const elements
|
|
4) initializing member references &
|
|
|
|
# Delegating constructors
|
|
|
|
C++11 also makes it possible to call a different constructor of the current
|
|
class on the initialization list. This feature is called delegating constructors.
|
|
*/
|
|
|
|
Base(int i, int j) : i(i), j(j) {
|
|
callStack.push_back("Base::Base(int, int)");
|
|
}
|
|
|
|
// ERROR: constructor cannot be virtual:
|
|
|
|
//virtual Base(float f){}
|
|
|
|
|
|
#if __cplusplus >= 201103L
|
|
|
|
/// C++11 initialize array/std containers in list initializtion.
|
|
Base(float f) : i(0), fs4{f,f,f,f}, vi{0,1,2,3} {
|
|
callStack.push_back("Base::Base(float)");
|
|
}
|
|
#endif
|
|
|
|
virtual ~Base() {
|
|
callStack.push_back("Base::~Base()");
|
|
}
|
|
|
|
void method() {
|
|
callStack.push_back("Base::method()");
|
|
int i = iAmbiguous;
|
|
i = iStatic;
|
|
i = iConstStatic;
|
|
}
|
|
|
|
void constMethod() const;
|
|
void constMethod(int *&) const;
|
|
|
|
//return references
|
|
|
|
int& getRefIPublic() {return this->iPublic;}
|
|
|
|
/// Value cannot be changed.
|
|
const int& getPrivateConstRef() const {return this->iPrivate;}
|
|
|
|
/// Value can be changed
|
|
int& getPrivateRef() {return this->iPrivate;}
|
|
|
|
// ERROR: const method cannot return noncosnt reference!
|
|
//int& getPrivateRef() const {return this->iPrivate;}
|
|
|
|
// ERROR: const method cannot return noncosnt pointer!
|
|
//int* getPrivateAddress() const {return &this->iPrivate;}
|
|
|
|
const int* getPrivateAddressConst() const {return &this->iPrivate;}
|
|
|
|
void methodAmbiguous(){callStack.push_back("Base::methodAmbiguous()");}
|
|
|
|
// virtual: decides on runtime based on object type
|
|
// http://stackoverflow.com/questions/2391679/can-someone-explain-c-virtual-methods
|
|
virtual void virtualMethod(){callStack.push_back("Base::virtualMethod()");}
|
|
|
|
virtual Base* covariantReturn() {
|
|
callStack.push_back("Base:covariantReturn()");
|
|
return new Base;
|
|
}
|
|
|
|
virtual void covariantArg(Base* b) {
|
|
callStack.push_back("Base:covariantArg()");
|
|
}
|
|
|
|
int i, j;
|
|
|
|
// ERROR: cannot initialize here.
|
|
//int initialized_outside_ctor = 0;
|
|
|
|
int iPublic;
|
|
int iAmbiguous;
|
|
|
|
int* is;
|
|
|
|
float fs4[4];
|
|
std::vector<int> vi;
|
|
|
|
mutable int mutableI;
|
|
// ERROR: statics can be changed in const functions by default.
|
|
//static mutable int staticMutableI;
|
|
|
|
/*
|
|
BAD every class must have an assigment operator.
|
|
But then, assigment does something like this->ic = other->ic
|
|
You could redefine the assigment, but still in your new definition ic cannot be changed.
|
|
<http://stackoverflow.com/questions/634662/non-static-const-member-cant-use-default-assignment-operator>
|
|
*/
|
|
|
|
// # static
|
|
|
|
static void staticMethod();
|
|
|
|
// ERROR: static cannot be const.
|
|
//static void staticMethod() const;
|
|
|
|
static int iStatic;
|
|
|
|
// Concflicts with static int.
|
|
//int iStatic;
|
|
|
|
// OK: because const static integral type
|
|
const static int iConstStatic = 0;
|
|
|
|
/*
|
|
# member initialization outside of constructor
|
|
*/
|
|
|
|
const int iConstInit = 0;
|
|
|
|
// ERROR: cannot initialize here unless const.
|
|
//static int iStatic = 0;
|
|
|
|
// ERROR: non-integral type.
|
|
//const static float fConstStatic = 0.0;
|
|
|
|
const static Member member;
|
|
// OK: why ok?
|
|
|
|
const static Member member2;
|
|
//default constructor works
|
|
|
|
//const static NoBaseNoMember(1);
|
|
/*
|
|
ERROR: non integral type must be init outside.
|
|
|
|
why integral types are an exception:
|
|
<http://stackoverflow.com/questions/13697265/static-const-double-cannot-have-an-in-class-initializer-why-is-it-so>
|
|
*/
|
|
|
|
class Nested {
|
|
public:
|
|
|
|
Nested() {
|
|
callStack.push_back("Base::Nested::Nested()");
|
|
int i = privateStaticInt;
|
|
//you have private access
|
|
}
|
|
|
|
Member m;
|
|
};
|
|
|
|
class Nested2 {
|
|
public:
|
|
|
|
Nested2() {
|
|
callStack.push_back("Base::Nested2::Nested2()");
|
|
}
|
|
|
|
Nested innerIn;
|
|
//inner one
|
|
|
|
::Nested innerOut;
|
|
//outter one
|
|
};
|
|
|
|
protected:
|
|
|
|
int iProtected;
|
|
void fProtected(){callStack.push_back("Base::fProtected()");}
|
|
|
|
private:
|
|
|
|
int iPrivate;
|
|
void fPrivate(){callStack.push_back("Base::fPrivate()");}
|
|
const static int privateStaticInt = 1;
|
|
|
|
typedef int PRIVATE_NESTED_INT;
|
|
|
|
};
|
|
|
|
/*
|
|
# friend
|
|
|
|
Allow external functions and other classes to access private memebers of this class.
|
|
|
|
Friendship is not automatically reflexive nor transitive.
|
|
|
|
One case in which friendship may be unavoidable is for operator overload of operators which cannot
|
|
be class members and must be implemented as external functions such as `operator<<`.
|
|
This happens because of the nature of operators, which may force them to be implemented outside the class.
|
|
|
|
<http://www.cplusplus.com/doc/tutorial/inheritance/>
|
|
|
|
# friend and templates
|
|
|
|
Things get complicated when friends and template classes interact:
|
|
|
|
<http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Ffriends_and_templates.htm>
|
|
*/
|
|
|
|
class FriendOfFriend;
|
|
|
|
class Friend {
|
|
|
|
public:
|
|
|
|
friend class FriendOfFriend;
|
|
|
|
Friend(int i) : i(i) {}
|
|
int getI(){return this->i;}
|
|
|
|
//this declaration says that `friendGetIPrivate(Base)` is a friend of this class.
|
|
//It will be defined outside the class.
|
|
friend int friendGetI(Friend f);
|
|
|
|
/* The same as friendGetI, but also defined inside the class. */
|
|
friend int friendGetIInnerDefine(Friend f) {
|
|
|
|
// ERROR: it is as if this were a friend external function, so there is no `this`.
|
|
//return this->i;
|
|
|
|
return f.i;
|
|
}
|
|
|
|
int getFriendI(FriendOfFriend f);
|
|
|
|
private:
|
|
|
|
int i;
|
|
void privateMethod(){};
|
|
};
|
|
|
|
/* cannot use the word friend here */
|
|
int friendGetI(Friend f){
|
|
|
|
// ERROR: this is a non-member function, so no `this`.
|
|
//return this->i;
|
|
|
|
return f.i;
|
|
}
|
|
|
|
class FriendOfFriend {
|
|
|
|
public:
|
|
|
|
FriendOfFriend(int i) : i(i) {}
|
|
int getFriendI(Friend f){return f.i;}
|
|
void callFriendPrivateMethod(Friend f){f.privateMethod();}
|
|
|
|
private:
|
|
|
|
int i;
|
|
};
|
|
|
|
// ERROR: friend used outside class.
|
|
//friend int friendGetI(Friend f){return f.i;}
|
|
|
|
// ERROR: not a friend because reflexivity is not automatic.
|
|
//int Friend::getFriendI(FriendOfFriend f) {return f.i;}
|
|
|
|
/*
|
|
# const method
|
|
|
|
Methods that cannot change the data of their object.
|
|
|
|
Inner workings: the hidden *this* pointer is downgraded to `const X*` when passing it to the function:
|
|
|
|
void method() const
|
|
|
|
becomes:
|
|
|
|
void method(const Class* this) const
|
|
|
|
instead of:
|
|
|
|
void method(Class* this) const
|
|
*/
|
|
void Base::constMethod() const {
|
|
// ERROR: cant assign member in const func.
|
|
//this->i = 2;
|
|
|
|
// ERROR: cant call non const method inside const method!
|
|
// as that method could change the object
|
|
//this->member.method();
|
|
|
|
// ERROR: cant assign member of a member in const method.
|
|
//this->member.i = 1;
|
|
|
|
/*
|
|
# mutable
|
|
|
|
OK
|
|
|
|
Mutable allows you to change it even in a const method.
|
|
|
|
Application to multithreading:
|
|
<http://stackoverflow.com/questions/105014/does-the-mutable-keyword-have-any-purpose-other-than-allowing-the-variable-to>
|
|
*/
|
|
this->mutableI = 1;
|
|
|
|
// Static changes can still be done.
|
|
this->iStatic = 1;
|
|
|
|
callStack.push_back("Base::constMethod()");
|
|
|
|
{
|
|
// ERROR: conversion from const Base* to Base*.
|
|
//Base* this2 = this;
|
|
|
|
const Base* this2const = this;
|
|
}
|
|
}
|
|
|
|
// ERROR must not ommit the const here either.
|
|
//void Base::constMethod () {}
|
|
|
|
/*
|
|
Cannot return a non const pointer from a const method, since this is const,
|
|
so all members are also const.
|
|
*/
|
|
void Base::constMethod(int *& ip) const {
|
|
// ERROR: invalid conversion.
|
|
//ip = &this->iPrivate;
|
|
}
|
|
|
|
int Base::iStatic = 0;
|
|
|
|
void Base::staticMethod() {
|
|
callStack.push_back("Base::staticMethod()");
|
|
|
|
// ERROR: no this!
|
|
//int i = this->i;
|
|
|
|
// OK: ok to use static vars
|
|
int i = iStatic;
|
|
}
|
|
|
|
// ERROR: static linkage, like in C static.
|
|
// meaning func only visible from current translational unit
|
|
//static void staticMethod()
|
|
|
|
// Must come outside
|
|
const Member Base::member2 = Member(1);
|
|
|
|
// ERROR: must be declared inside.
|
|
//int Base::k;
|
|
|
|
// # virtual
|
|
|
|
class BaseAbstract {
|
|
|
|
public:
|
|
|
|
// Can be called in derived classes init list.
|
|
BaseAbstract(){}
|
|
|
|
virtual ~BaseAbstract() {}
|
|
void method() { callStack.push_back("BaseAbstract::method()"); }
|
|
void methodAmbiguous() {callStack.push_back("BaseAbstract::methodAmbiguous()"); }
|
|
virtual void virtualMethod() { callStack.push_back("BaseAbstract::virtualMethod()"); }
|
|
virtual void pureVirtual() = 0;
|
|
|
|
// BAD: won't work: must implement on derived class only.
|
|
//virtual void pureVirtualImplementedOtherBase() = 0;
|
|
|
|
int i;
|
|
int iAmbiguous;
|
|
|
|
private:
|
|
|
|
// This can/must still be implemented on the base class, even if private!
|
|
virtual void privatePureVirtual() = 0;
|
|
|
|
// How private pure virtual can be useful.
|
|
void usefulPrivatePureVirtual() {
|
|
callStack.push_back("common before");
|
|
privatePureVirtual();
|
|
callStack.push_back("common after");
|
|
}
|
|
};
|
|
|
|
class PureVirtualImplementedOtherBase {
|
|
public:
|
|
void pureVirtual() {
|
|
callStack.push_back("PureVirtualImplementedOtherBase::pureVirtual()");
|
|
}
|
|
private:
|
|
void privatePureVirtual() {
|
|
callStack.push_back("PureVirtualImplementedOtherBase::privatePureVirtual()");
|
|
}
|
|
};
|
|
|
|
class DerivedAbtractAndImplementator : BaseAbstract, PureVirtualImplementedOtherBase {
|
|
//public:
|
|
//void pureVirtual()
|
|
//{
|
|
//callStack.push_back("PureVirtualImplementedOtherBase::pureVirtual()");
|
|
//}
|
|
//private:
|
|
//void privatePureVirtual()
|
|
//{
|
|
//callStack.push_back("PureVirtualImplementedOtherBase::privatePureVirtual()");
|
|
//}
|
|
};
|
|
|
|
class InheritOverloadBase {
|
|
public:
|
|
void overload(){}
|
|
void not_overload(){}
|
|
};
|
|
|
|
class InheritOverloadDerived : public InheritOverloadBase {
|
|
public:
|
|
// `using` is required, or f(int) hides `f()`.
|
|
using InheritOverloadBase::overload;
|
|
void overload(int i) {
|
|
overload();
|
|
// This one does not reqire using becase it is not overloaded.
|
|
not_overload();
|
|
}
|
|
};
|
|
|
|
#if __cplusplus >= 201103L
|
|
class InheritingCtorBase {
|
|
public:
|
|
int i;
|
|
InheritingCtorBase() : i(0) {}
|
|
InheritingCtorBase(int i) : i(i) {}
|
|
};
|
|
|
|
class InheritingCtorDerived : public InheritingCtorBase {
|
|
public:
|
|
// Will define InheritingCtorDerived(int) and the copy constructor.
|
|
using InheritingCtorBase::InheritingCtorBase;
|
|
};
|
|
#endif
|
|
|
|
class VirtualFromCtorBase {
|
|
public:
|
|
int i;
|
|
int j;
|
|
VirtualFromCtorBase() {
|
|
// Calls base::a, not derived::a
|
|
this->i = a();
|
|
// LINKER ERROR: undefined reference to b().
|
|
//j = b();
|
|
}
|
|
virtual int a() { return 0; }
|
|
virtual int b() = 0;
|
|
};
|
|
|
|
class VirtualFromCtorDerived : public VirtualFromCtorBase {
|
|
public:
|
|
virtual int a() { return 1; }
|
|
virtual int b() { return 10; }
|
|
};
|
|
|
|
class VirtualFromCtor2PhaseBase {
|
|
public:
|
|
int i;
|
|
int j;
|
|
VirtualFromCtor2PhaseBase() {}
|
|
void init() {
|
|
this->i = a();
|
|
this->j = b();
|
|
}
|
|
virtual int a() { return 0; }
|
|
virtual int b() = 0;
|
|
};
|
|
|
|
class VirtualFromCtor2PhaseDerived : public VirtualFromCtor2PhaseBase {
|
|
public:
|
|
VirtualFromCtor2PhaseDerived() { init(); }
|
|
virtual int a() { return 1; }
|
|
virtual int b() { return 10; }
|
|
};
|
|
|
|
class MultipleInheritanceConflictBase1 {
|
|
public:
|
|
const static int is = 1;
|
|
int i;
|
|
void f(){}
|
|
};
|
|
|
|
class MultipleInheritanceConflictBase2 {
|
|
public:
|
|
const static int is = 2;
|
|
int i;
|
|
void f(){}
|
|
};
|
|
|
|
class MultipleInheritanceConflictDerived :
|
|
MultipleInheritanceConflictBase1,
|
|
MultipleInheritanceConflictBase2
|
|
{};
|
|
|
|
class BaseProtected {
|
|
public:
|
|
|
|
BaseProtected(){callStack.push_back("BaseProtected::BaseProtected()");}
|
|
BaseProtected(int i){callStack.push_back("BaseProtected::BaseProtected(int)");}
|
|
~BaseProtected(){callStack.push_back("BaseProtected::~BaseProtected()");}
|
|
};
|
|
|
|
class BasePrivate {
|
|
public:
|
|
BasePrivate(){callStack.push_back("BasePrivate::BasePrivate()");}
|
|
BasePrivate(int i){callStack.push_back("BasePrivate::BasePrivate(int)");}
|
|
~BasePrivate(){callStack.push_back("BasePrivate::~BasePrivate()");}
|
|
};
|
|
|
|
class Derived : private BasePrivate {};
|
|
|
|
class Class :
|
|
public Base,
|
|
//public Base, // ERROR: duplicate.
|
|
//public Derived, // WARN: cannot use BasePrivate inside: ambiguous.
|
|
protected BaseProtected,
|
|
private BasePrivate,
|
|
public BaseAbstract
|
|
{
|
|
public:
|
|
|
|
/*
|
|
calls base constructors first
|
|
*/
|
|
Class() : i(0), z(1) {
|
|
callStack.push_back("Class::Class()");
|
|
}
|
|
|
|
Class(int i) : i(i), z(0) {
|
|
callStack.push_back("Class::Class(int)");
|
|
}
|
|
|
|
/*
|
|
calls specific base constructors instead of default ones
|
|
another application os initialization lists
|
|
|
|
works even if the BaseAbstract class is abstract!
|
|
this is the only place you can do that: init list of derived classes
|
|
*/
|
|
Class(int i, int z) : Base(i,z), BaseProtected(i), BasePrivate(i), BaseAbstract(), i(i), z(z) {
|
|
callStack.push_back("Class::Class(int, int)");
|
|
}
|
|
|
|
// WARN: BaseAbstract will be init after TODO ?
|
|
//Class() : BaseAbstract(), Base(i,z), BaseProtected(i), BasePrivate(i), i(i), z(z)
|
|
|
|
//try catch in case base constructor can throw exceptions
|
|
Class(int i, int j, int z) try : Base(i,j), i(i), z(z) {
|
|
callStack.push_back("Class::Class(int, int, int)");
|
|
}
|
|
catch(const std::exception &e) {
|
|
throw e;
|
|
}
|
|
|
|
Class(Member m) : m(m) {
|
|
//this->m = m;
|
|
//BAD: m constructor would be called, but this is useless since we have already called it!
|
|
//to construct it before.
|
|
//This is an application of initialization constructors.
|
|
|
|
callStack.push_back("Class::Class(Member)");
|
|
}
|
|
|
|
/*
|
|
Copy constructor.
|
|
|
|
Classes already have this by default.
|
|
|
|
Useful to customize if class does dynamic allocation!
|
|
*/
|
|
|
|
Class(const Class& c) : i(c.i), z(c.z), m(c.m) {
|
|
callStack.push_back("Class::Class(Class)");
|
|
}
|
|
|
|
// Classes don't have constructors from base by default.
|
|
Class(const Base& b) : Base(b) {
|
|
callStack.push_back("Class::Class(Base)");
|
|
}
|
|
|
|
/*
|
|
Also calls Base destructor after
|
|
*/
|
|
~Class() { callStack.push_back("Class::~Class()"); }
|
|
|
|
// Called method overwriding.
|
|
void method() { callStack.push_back("Class::method()"); }
|
|
|
|
// OK.
|
|
template<class C=int>
|
|
void methodTemplate() {
|
|
callStack.push_back("Class::methodTemplate()");
|
|
}
|
|
|
|
// Different than overwriding non virtual methods. see polymorphism.
|
|
void virtualMethod() { callStack.push_back("Class::virtualMethod()"); }
|
|
|
|
// OK: only difference: if you have a pointer to this class,
|
|
// you can only use virtual if this is declared virtual.
|
|
//virtual void virtualMethod(){callStack.push_back("Class::virtualMethod()");}
|
|
|
|
// Definition obligatory if you want to create objects of this class.
|
|
void pureVirtual() { callStack.push_back("Class::pureVirtual()"); }
|
|
|
|
// ERROR: unlike function overloading, polyomorphism is decided at runtime
|
|
// and therefore return type must be the same as in declaration
|
|
//int pureVirtual(){return 1;}
|
|
|
|
// OK because Class is derived from Base
|
|
// called "covariant return type".
|
|
virtual Class* covariantReturn() {
|
|
callStack.push_back("Class:covariantReturn()");
|
|
return new Class;
|
|
}
|
|
|
|
// ERROR: invalid covariant
|
|
//virtual Class invalidCovariantReturn(){return Class();}
|
|
|
|
virtual void covariantArg(Class* c) {
|
|
callStack.push_back("Class:covariantArg()");
|
|
}
|
|
|
|
int i;
|
|
int z;
|
|
Member m;
|
|
Nested nested;
|
|
//Base nested class visible from here
|
|
|
|
|
|
private:
|
|
|
|
virtual void privatePureVirtual(){callStack.push_back("Class:privatePureVirtual()");};
|
|
};
|
|
|
|
//nested
|
|
|
|
// OK: you can see the nested class from derived classes
|
|
class NestedDerived : Class::Nested{};
|
|
|
|
class Class2 : public Base {
|
|
public:
|
|
|
|
Class2(){}
|
|
void pureVirtual(){callStack.push_back("Class2::pureVirtual()");}
|
|
|
|
// OK: you can override the Nested class from the Base also
|
|
class Nested{};
|
|
};
|
|
|
|
class ClassCast {
|
|
ClassCast(Class c){}
|
|
};
|
|
|
|
// ERROR:
|
|
//ClassDefault::ClassDefault(int i=0){}
|
|
|
|
/*
|
|
Illustrates the copy and swap idiom and related concepts like move contruction.
|
|
*/
|
|
class CopyAndSwap {
|
|
public:
|
|
|
|
int *is;
|
|
std::size_t n;
|
|
|
|
CopyAndSwap(std::size_t n, int val) : n(n) {
|
|
is = new int[n];
|
|
for (std::size_t i = 0; i < n; ++i) {
|
|
is[i] = val;
|
|
}
|
|
}
|
|
|
|
~CopyAndSwap(){
|
|
delete[] is;
|
|
}
|
|
|
|
CopyAndSwap& operator=(const CopyAndSwap& rhs) {
|
|
delete[] is;
|
|
is = new int[rhs.n];
|
|
return *this;
|
|
}
|
|
|
|
CopyAndSwap(const CopyAndSwap& other) {
|
|
}
|
|
};
|
|
|
|
//design patterns
|
|
//{
|
|
|
|
|
|
//VisibleInnerIterable
|
|
//{
|
|
/*
|
|
this is the best way I could find to make a member
|
|
iterable object such as a container available outside
|
|
|
|
design goal:
|
|
|
|
- to change container type, you only change a single typedef
|
|
|
|
difficulty:
|
|
|
|
- there is no `Iterator` interface that iterates over anything in the stdlib
|
|
for performance reasons.
|
|
|
|
By iterable understand somtehing that has an `::iterator`,
|
|
a `begin()` and an `end()` methods, like stl containers
|
|
*/
|
|
class VisibleInnerIterable {
|
|
public:
|
|
|
|
VisibleInnerIterable();
|
|
|
|
typedef std::vector<int> Iterable;
|
|
|
|
const Iterable& getIterable();
|
|
|
|
private:
|
|
|
|
Iterable iterable;
|
|
};
|
|
|
|
VisibleInnerIterable::VisibleInnerIterable() : iterable{0,1,2} {}
|
|
|
|
const VisibleInnerIterable::Iterable& VisibleInnerIterable::getIterable() {
|
|
return iterable;
|
|
}
|
|
//}
|
|
//}
|
|
//}
|
|
|
|
//struct
|
|
|
|
template<class T>
|
|
struct BaseStruct {
|
|
T i;
|
|
BaseStruct(T i) : i(i) {}
|
|
|
|
protected:
|
|
int iProtected;
|
|
|
|
private:
|
|
int iPrivate;
|
|
};
|
|
|
|
struct DerivedStruct : BaseStruct<int> {
|
|
DerivedStruct(int i) : BaseStruct(i) {
|
|
iProtected = i;
|
|
}
|
|
};
|
|
|
|
|
|
// #global scope
|
|
|
|
int global = 0;
|
|
|
|
// Differently from C, computations can be done to initialize globals.
|
|
|
|
int global2 = global+1;
|
|
int ret1() {
|
|
callStack.push_back("before main!");
|
|
return 1;
|
|
}
|
|
int global3 = ret1();
|
|
|
|
// ERROR: arbitrary computations cannot be done however, only those that initialize a global
|
|
|
|
//global = 1;
|
|
//if (1){}
|
|
//callStack.push_back("global");
|
|
|
|
//function
|
|
|
|
//pass by reference
|
|
|
|
//http://stackoverflow.com/questions/114180/pointer-vs-reference
|
|
|
|
void byref(int& i) {i++;}
|
|
void bypointer(int *i) {(*i)++;}
|
|
|
|
void bypointerConst(const int*& ip, const int*& jp) {
|
|
ip = jp;
|
|
}
|
|
|
|
//return reference from function
|
|
|
|
int getInt() {return 0;}
|
|
|
|
int getIntVar() {
|
|
int i = 0;
|
|
return i;
|
|
}
|
|
|
|
/*
|
|
int& getIntRef() {
|
|
int i = 0;
|
|
return i;
|
|
}
|
|
*/
|
|
// WARN: reference to local var returned
|
|
|
|
/*
|
|
OK the returned i reference is not local
|
|
*/
|
|
int& getIntRef(int& i) {
|
|
i++;
|
|
return i;
|
|
}
|
|
|
|
/*
|
|
The returned i reference cannot be modified.
|
|
*/
|
|
const int& getIntConstRef(int& i) {
|
|
i++;
|
|
return i;
|
|
}
|
|
|
|
std::string getString() {return "abc";}
|
|
|
|
//default args. C++ only. creates several name mungled functions on the assembly code.
|
|
|
|
int DefaultArgs(int i, int j=0) { return i + j; }
|
|
|
|
// ERROR: Cannot use one argument as the default for the other.
|
|
//int DefaultArgs(float f, float f2=f) { return f + f2; }
|
|
|
|
// ERROR: no compound literals in c++
|
|
//void foo (int bar[] = (int[2]){0 ,1});
|
|
|
|
//function overloading
|
|
|
|
void overload(int i){callStack.push_back("overload(int)");}
|
|
void overload(int i, int j){callStack.push_back("overload(int,int)");}
|
|
void overload(float i){callStack.push_back("overload(float)");}
|
|
void overload(float i, float j, float k=0.f){callStack.push_back("overload(float,float,float=)");}
|
|
|
|
// OK even if return type is different all is decided at compile time.
|
|
|
|
//int overload(int i, int j, int k){return 1;}
|
|
|
|
// ERROR: conflict with int.
|
|
|
|
//void overload(const int i){}
|
|
|
|
// ERROR: cannot differentiate by output since output is used to decide if other parts of code make sense.
|
|
|
|
//int overload(){return 0;}
|
|
//float overload(){return 0.f;}
|
|
|
|
// ERROR: conflict with int int
|
|
|
|
//void overload(int i, int j=0){cout << "int int=";}
|
|
|
|
// BAD: compiles, but is useless to give a default,
|
|
// since when calling, caller is *forced* to give a value for j
|
|
// or wil get `call is ambiguous` compile time error
|
|
// because compiler cannot decide between
|
|
// here the default arg can be usefull for a call of type float float.
|
|
|
|
//void overload(float i, float j=1){cout << "float float=";}
|
|
|
|
// TODO: why does this compile, that is, how not to make an ambiguous call with overload(int).
|
|
|
|
void overloadValAddr(const int i){}
|
|
void overloadValAddr(const int& i){}
|
|
|
|
void overloadBase(Base b){}
|
|
void overloadBase(BaseProtected b){}
|
|
|
|
#if __cplusplus >= 201103L
|
|
|
|
/* pair of function overload based only on if argument is an rvalue or a lvalue */
|
|
std::string overloadRLvalue(int& i) {
|
|
return "lval";
|
|
}
|
|
|
|
std::string overloadRLvalue(int&& i) {
|
|
return "rval";
|
|
}
|
|
|
|
/*
|
|
ERROR: ambiguous with both of the above, because in C++:
|
|
|
|
int i = lvalue;
|
|
|
|
Leads to copy construction (ambiguous with the `&` overload).
|
|
|
|
int i = rvalue;
|
|
|
|
Leads to move construction (ambiguous with the `&&` overload).
|
|
*/
|
|
/*
|
|
std::string overloadRLvalue(int i) {
|
|
return "val";
|
|
}
|
|
*/
|
|
#endif
|
|
|
|
//default args
|
|
|
|
void defaultArgProto(int i=0);
|
|
void defaultArgProto(int i){}
|
|
|
|
// BAD: usually not what you want
|
|
// since includers will not see the default version
|
|
|
|
void defaultArgDef(int i);
|
|
void defaultArgDef(int i=0){}
|
|
|
|
// ERROR: default cannot go in declaration and definition
|
|
|
|
//void defaultArgBoth(int i=0);
|
|
//void defaultArgBoth(int i=0){}
|
|
|
|
int def_no_argname(int){return 1;}
|
|
int def_no_argname(int, int){return 2;}
|
|
|
|
/*
|
|
# auto arguments
|
|
*/
|
|
|
|
/*ERROR: no you can't*/
|
|
/*
|
|
int func_auto(auto a){
|
|
++a;
|
|
return (int)a;
|
|
}
|
|
*/
|
|
|
|
/*
|
|
# operator overload
|
|
|
|
Like regular functions, C++ also allows operators to be overloaded
|
|
|
|
This is not only eye candy, but also allows developpers to forget if they are dealing
|
|
with base types or not, thus making code easier to modify: if we ever decide to move
|
|
from base types to classes we just have to implement the operator overload on classes.
|
|
|
|
Great tutorial: <http://stackoverflow.com/questions/4421706/operator-overloading?rq=1>
|
|
|
|
Good tutorial, specially on how to implement `=`, `+=` and `+` cases:
|
|
<http://courses.cms.caltech.edu/cs11/material/cpp/donnie/cpp-ops.html>
|
|
|
|
The following operators can all be overloaded:
|
|
|
|
+ - * / = < > += -= *= /= << (shift left) >> (shift right)
|
|
<<= >>= == != <= >= ++ -- % & ^ ! |
|
|
~ &= ^= |= && || %= [] () , ->* -> new
|
|
delete new[] delete[]
|
|
|
|
- typecast operator overload `int()`, `float()`, etc.
|
|
|
|
Member or not
|
|
|
|
Certain operators can be both member functions and free functions.
|
|
This includes most operators such as `+`, `=`, `+=` and others.
|
|
See: <http://stackoverflow.com/a/4421729/895245> for a discussion on how to decide
|
|
between them.
|
|
|
|
One question is that being non member improves the incapsulation, since then those
|
|
functions do not have access to private members, and thus do not reflect changes that are
|
|
otherwise invisible.
|
|
|
|
Certain operators *cannot* be member functions, such as `<<`.
|
|
|
|
Other *must* be members. Those include:
|
|
|
|
- `=` (assignment)
|
|
- `[]` (array subscription),
|
|
- `->` (member access)
|
|
- `()` (function call)
|
|
*/
|
|
|
|
/*
|
|
ERROR: One of the arguments must be a Class or Enum.
|
|
|
|
Just imagine the havoc if this were possible! =)
|
|
*/
|
|
|
|
//int operator+(int i, int j){return i + j + 1;}
|
|
|
|
/*
|
|
class that shows the ideal methods of operator overloading.
|
|
*/
|
|
class OperatorOverload {
|
|
|
|
public:
|
|
|
|
int i;
|
|
|
|
OperatorOverload() { this->i = 0; }
|
|
OperatorOverload(int i) { this->i = i; }
|
|
|
|
/*
|
|
operator=
|
|
|
|
Special care must be taken with `=` when memory is dynamically alocated because
|
|
of copy and swap idiom questions.
|
|
|
|
This is not the case for this simple class.
|
|
|
|
Return non const reference
|
|
|
|
Return a *non* const reference because the following is possible for base types:
|
|
|
|
(a = b) = c
|
|
|
|
which is the same as:
|
|
|
|
a = b
|
|
a = c
|
|
|
|
so this obscure syntax should also work for classes.
|
|
*/
|
|
OperatorOverload& operator=(const OperatorOverload& rhs) {
|
|
this->i = rhs.i;
|
|
return *this;
|
|
}
|
|
|
|
/*
|
|
operator+=
|
|
|
|
Implement the compound assign, and the non compound in terms of the compound.
|
|
|
|
Must return a non-const reference for the same reason as `=`.
|
|
*/
|
|
OperatorOverload& operator+=(const OperatorOverload& rhs) {
|
|
this->i += rhs.i;
|
|
return *this;
|
|
}
|
|
|
|
/*
|
|
operator++
|
|
|
|
Post and pre increment are both impemented via this operator.
|
|
|
|
<http://stackoverflow.com/questions/6375697/overloading-pre-increment-operator>
|
|
*/
|
|
const OperatorOverload& operator++() {
|
|
this->i++;
|
|
return *this;
|
|
}
|
|
|
|
/*
|
|
Ambiguous call.
|
|
|
|
This cannot be distinguished from the member method,
|
|
since the member method gets am implicit `this` first argument.
|
|
|
|
Therefore any call to this operator would give an ambiguous message
|
|
if this were defined.
|
|
|
|
The effect is the same as the non member function, but the non member is preferred
|
|
because it improves encapsulation.
|
|
*/
|
|
|
|
/*
|
|
OperatorOverload operator+(OperatorOverload i, OperatorOverload j){
|
|
OperatorOverload ret;
|
|
ret.i = i.i + j.i + 1;
|
|
return ret;
|
|
}
|
|
*/
|
|
|
|
/*
|
|
# typecast overload
|
|
|
|
Automatic conversions will be done using it.
|
|
|
|
Notable example on the stdlib: `ifstream::operator bool()` to be able to do `while(getline)`
|
|
becaues getline returns the updated ifstream.
|
|
*/
|
|
|
|
operator bool() const { return i % 2 == 1; }
|
|
operator int() const { return i + 1; }
|
|
operator float() const { return ((float)i) + 0.5; }
|
|
};
|
|
|
|
/*
|
|
operator+
|
|
|
|
Implemented in terms of the compound assign.
|
|
|
|
Should be const because the following does nothing:
|
|
|
|
(a + b) = c
|
|
|
|
Should be an external method, since it is just a function of `+=`.
|
|
*/
|
|
|
|
OperatorOverload operator+ (const OperatorOverload& lhs, const OperatorOverload& rhs) {
|
|
return OperatorOverload(lhs) += rhs;
|
|
}
|
|
|
|
/*
|
|
Comparison operators: only tow are needed: `==` and `<`.
|
|
|
|
The other are functions of those two.
|
|
|
|
It is recommended to implement them as non-member functions to increase incapsulation.
|
|
*/
|
|
|
|
inline bool operator==(const OperatorOverload& lhs, const OperatorOverload& rhs) {return lhs.i == rhs.i;}
|
|
inline bool operator!=(const OperatorOverload& lhs, const OperatorOverload& rhs) {return !operator==(lhs,rhs);}
|
|
inline bool operator< (const OperatorOverload& lhs, const OperatorOverload& rhs) {return lhs.i < rhs.i;}
|
|
inline bool operator> (const OperatorOverload& lhs, const OperatorOverload& rhs) {return operator< (rhs,lhs);}
|
|
inline bool operator<=(const OperatorOverload& lhs, const OperatorOverload& rhs) {return !operator> (lhs,rhs);}
|
|
inline bool operator>=(const OperatorOverload& lhs, const OperatorOverload& rhs) {return !operator< (lhs,rhs);}
|
|
|
|
/*
|
|
operator<<
|
|
|
|
`<<` **cannot** be a member method, because if it were then
|
|
its first argument would be an implicit `Class` for the `this`,
|
|
but the first argument of `<<` must be the `ostream`.
|
|
|
|
Therefore it must be a free method outside of a class.
|
|
|
|
It is likely that it will need to be a friend of the class in order
|
|
to see its internal fields. This may not be the case in this overly simplified example.
|
|
*/
|
|
|
|
std::ostream& operator<<(std::ostream& os, const OperatorOverload& c) {
|
|
os << c.i;
|
|
return os;
|
|
}
|
|
|
|
/*
|
|
# number of arguments
|
|
|
|
One major difference between regular functions and operators is that operators can only
|
|
have fixed number of arguments, because they have a very peculiar syntax.
|
|
|
|
For example, how could a ternary multiplication possibly be called? ` a * b ???? c` ?
|
|
|
|
There are some operators which exist for multiple numbers of arguments with different meaning:
|
|
|
|
- `-` with one argument: unary minus
|
|
- `-` with two arguments: subtraction
|
|
|
|
- `*` with one argument: dereference
|
|
- `*` with two arguments: multiplication
|
|
|
|
For this reason, we must take into account that member operator overloads *already have one extra argument*,
|
|
which is the `this` pointer, which is always passed as a first hidden parameter of member functions.
|
|
*/
|
|
|
|
/*
|
|
A failed attemtpt to add the middle handside to `operator*`.
|
|
|
|
ERROR: operator* must have one or two arguments.
|
|
*/
|
|
/*
|
|
const OperatorOverload operator* (const OperatorOverload& lhs, const OperatorOverload& mhs, const OperatorOverload& rhs){
|
|
return OperatorOverload(lhs.i * mhs.i * rhs.i);
|
|
}
|
|
*/
|
|
|
|
/*
|
|
operator*
|
|
|
|
operator* can be two things:
|
|
|
|
- multiplication `a * b` if it has two arguments (or one in a member method)
|
|
- dereference `*ptr` if it has one argument (or none in a member method)
|
|
|
|
It is only differenced by the number of arguments.
|
|
*/
|
|
|
|
/*
|
|
This exists because it is the dereference operator.
|
|
|
|
This is implemented on classes which represent pointers, such as `shared_ptr`,
|
|
which is not the case for this class.
|
|
*/
|
|
|
|
/*
|
|
Dereference operator.
|
|
|
|
This should not be implemented for this class since it makes no (usual) sense,
|
|
it is just to illustrate that it is possible.
|
|
*/
|
|
int operator* (const OperatorOverload& rhs){
|
|
return rhs.i;
|
|
}
|
|
|
|
OperatorOverload operator* (const OperatorOverload& lhs, const OperatorOverload& rhs){
|
|
return OperatorOverload(lhs.i * rhs.i);
|
|
}
|
|
|
|
/*
|
|
operator-
|
|
|
|
- `-` with one argument: unary minus
|
|
- `-` with two arguments: subtraction
|
|
|
|
*/
|
|
|
|
/* Can be defined in terms of * if you class implements it. */
|
|
const OperatorOverload operator- (const OperatorOverload& rhs){
|
|
return OperatorOverload(-1) * rhs;
|
|
}
|
|
|
|
/* Defined in terms of unary minus and +. */
|
|
const OperatorOverload operator- (const OperatorOverload& lhs, const OperatorOverload& rhs){
|
|
return lhs + (-rhs);
|
|
}
|
|
|
|
/*
|
|
operator overload and templates
|
|
|
|
Operator overload and templates do not play very well together
|
|
because operator overload leads to special function calling syntax,
|
|
which does not go well with the template calling syntax.
|
|
*/
|
|
|
|
template <class T>
|
|
T operator/(const T& i, const T& j) {return i + j;}
|
|
|
|
/*
|
|
#namespaces
|
|
*/
|
|
|
|
// ERROR: same naming rules as vars
|
|
//namespace 2D{}
|
|
|
|
// BAD: by convention, namespaces start with lower case
|
|
namespace D2{}
|
|
|
|
int i;
|
|
|
|
void f() {
|
|
callStack.push_back("::f");
|
|
}
|
|
|
|
void prototype();
|
|
|
|
namespace namea {
|
|
|
|
int in_namea_only = 0;
|
|
|
|
class C {
|
|
public:
|
|
C() {
|
|
callStack.push_back("namea::C");
|
|
}
|
|
};
|
|
|
|
namespace nameaa {
|
|
int i;
|
|
|
|
void f() {
|
|
callStack.push_back("nameaa::f");
|
|
}
|
|
|
|
class C {
|
|
public:
|
|
C() {
|
|
callStack.push_back("nameaa::C");
|
|
}
|
|
};
|
|
}
|
|
|
|
namespace nameab {
|
|
int i;
|
|
|
|
void f() {
|
|
callStack.push_back("namea::nameab::f");
|
|
|
|
::i = 0;
|
|
i = 0; //namea::nameab::i
|
|
nameaa::i = 0; //namea::nameaa::i
|
|
|
|
using namespace nameaa;
|
|
//only affects this function. see C::C() at the f() call
|
|
}
|
|
|
|
class C :
|
|
public namea::C
|
|
//public C
|
|
// ERROR: refers to current incomplete C already
|
|
//not existem namea::C
|
|
{
|
|
C() {
|
|
callStack.push_back("namea::nameab::C");
|
|
f();
|
|
//no ambiguity because using inside f() only afects the function
|
|
}
|
|
};
|
|
}
|
|
|
|
int i;
|
|
|
|
void f() {
|
|
::i = 0;
|
|
i = 0; //namea::i
|
|
namea::i = 0;
|
|
nameaa::i = 0; //namea::nameaa::i
|
|
callStack.push_back("namea::f");
|
|
}
|
|
}
|
|
|
|
namespace namea {
|
|
//can add new members
|
|
int j;
|
|
void newFunc(){}
|
|
class B{};
|
|
|
|
// ERROR: redefinition
|
|
//int i;
|
|
|
|
// Implementation of namea::prototype.
|
|
//void prototype(){}
|
|
}
|
|
|
|
// ERROR: must be declared/defined inside.
|
|
//namea::i = 0;
|
|
//void namea::prototype(){}
|
|
//int namea::j;
|
|
//void namea::g(){}
|
|
//class namea::B{};
|
|
|
|
// ERROR.
|
|
//template<class T> namespace t {}
|
|
|
|
// # ADL
|
|
|
|
namespace adl0 {
|
|
|
|
struct s {};
|
|
|
|
int adl(struct s s){
|
|
return 0;
|
|
}
|
|
|
|
int i;
|
|
|
|
int adlNoType(int i){
|
|
return 0;
|
|
}
|
|
|
|
int adlMultiArg(int i, struct s s, int j){
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
namespace adl1 {
|
|
|
|
struct s {};
|
|
|
|
int adl(struct s s){
|
|
return 1;
|
|
}
|
|
|
|
int i;
|
|
|
|
int adlNoType(int i){
|
|
return 1;
|
|
}
|
|
|
|
int adl0FromAdl1(struct adl0::s s) {
|
|
return 1;
|
|
}
|
|
|
|
int adl0And1FromAdl1(struct adl0::s s0, struct s s1) {
|
|
return 1;
|
|
}
|
|
|
|
float adl01(struct adl0::s s, struct s s1){
|
|
return 0.5;
|
|
}
|
|
}
|
|
|
|
namespace adl0 {
|
|
float adl01(struct s s, struct adl1::s s1){
|
|
return 0.5;
|
|
}
|
|
}
|
|
|
|
// #preprocessor
|
|
|
|
// The C++ preprocessor it Turing complete by mistake.
|
|
//
|
|
// This leads to the concept of Template Metaprogramming,
|
|
// which allows you to write code that is ultra DRY / runs fast but is very large.
|
|
// TODO confirm.
|
|
|
|
// #template
|
|
|
|
/*
|
|
TODO what is this?? why does it compile? how to call this func?
|
|
*/
|
|
|
|
template <class T>
|
|
int templateTODO(T /*no param name!*/){
|
|
//return i + 1;
|
|
return 1;
|
|
}
|
|
|
|
template<class T>
|
|
T templateAdd(T t0, T t1) {
|
|
return t0 + t1;
|
|
}
|
|
|
|
// # template integer parameter
|
|
template<int N>
|
|
int templateAddInt(int t) {
|
|
return t + N;
|
|
}
|
|
|
|
// # template recursion
|
|
|
|
template<int N>
|
|
int factorial() {
|
|
return N*factorial<N-1>();
|
|
}
|
|
|
|
//without this template specialization, compilation error
|
|
//for me, blows max template recursion depth of 1024
|
|
//this can be reset with `-ftemplate-depth`
|
|
template<>
|
|
int factorial<0>() {
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
# template template parameters
|
|
*/
|
|
|
|
template<typename T>
|
|
class TemplateTemplateParam {
|
|
public:
|
|
TemplateTemplateParam(){}
|
|
TemplateTemplateParam(T t) : t(t) {}
|
|
T t;
|
|
};
|
|
|
|
template<template<typename T> class U>
|
|
class TemplateTemplateInt {
|
|
public:
|
|
U<int> t;
|
|
};
|
|
|
|
/*
|
|
template<class T>
|
|
class TemplateTemplateIntNotATemplate {
|
|
public:
|
|
T<int> t;
|
|
};
|
|
*/
|
|
/*
|
|
ERROR T is not a template.
|
|
|
|
Must use a template template parameter.
|
|
*/
|
|
|
|
/*
|
|
A case in which using a template template would be a better choice.
|
|
*/
|
|
template<class T, class V>
|
|
class TemplateTemplateWouldBeBetter {
|
|
public:
|
|
T t;
|
|
V v;
|
|
|
|
bool equal(){return t == v.t;}
|
|
};
|
|
|
|
/*
|
|
Illustrates a case in which template template is a good design choice.
|
|
*/
|
|
template<typename T, template<typename U> class V>
|
|
class TemplateTemplate {
|
|
public:
|
|
|
|
/* the template template enforces that T be used twice,
|
|
once for each memeber type, if that is what this class intends to happen */
|
|
T t;
|
|
V<T> v;
|
|
|
|
bool equal(){return t == v.t;}
|
|
};
|
|
|
|
/*
|
|
# template default parameters
|
|
*/
|
|
|
|
template<typename T=int, template <typename U> class TT = TemplateTemplateParam, int N=1 >
|
|
T templateDefault(T t, TT<T> tt) {
|
|
return t + tt.t + N;
|
|
}
|
|
|
|
// TODO is this possible? g++ 4.8 compiles, clang++ 3.2 says that the first T overshadows the T in `template <typename T>`
|
|
//template<typename T, template <typename T> class TT = TemplateTemplateParam > return t + tt.t + N; }
|
|
|
|
template<typename T, T t>
|
|
T TemplateReuseType() {
|
|
return t;
|
|
}
|
|
|
|
// # template specialization
|
|
|
|
template<typename T, typename U>
|
|
double templateSpec(T t, U u) {
|
|
return t + u;
|
|
}
|
|
|
|
template<>
|
|
double templateSpec<double,double>(double t, double u) {
|
|
// ERROR: T cannot be used anymore in this specialization.
|
|
//T res;
|
|
|
|
return t + u + 1.1;
|
|
}
|
|
|
|
// ERROR: template specialization of a single template parameter not allowed
|
|
/*
|
|
template<typename U>
|
|
double templateSpec<double,U>(double t, U u) {
|
|
return t + u + 1.0;
|
|
}
|
|
|
|
template<typename T>
|
|
double templateSpec<T,double>(T t, double u) {
|
|
return t + u + 0.1;
|
|
}
|
|
*/
|
|
|
|
// # template argument deduction
|
|
|
|
template<typename U>
|
|
U templateArgDeduct(U u) {
|
|
return u;
|
|
}
|
|
|
|
template<>
|
|
double templateArgDeduct(double u) {
|
|
return u + 1.0;
|
|
}
|
|
|
|
template<typename T>
|
|
T templateArgDeductReturn() {
|
|
return 0;
|
|
}
|
|
|
|
template<typename T>
|
|
T templateArgDeductLocal() {
|
|
return 0;
|
|
}
|
|
|
|
template<typename T, typename U>
|
|
double templateArgDeductNotLast(T t) {
|
|
U u = 0;
|
|
return t + u;
|
|
}
|
|
|
|
template<typename T>
|
|
T templateArgTemplateArg(TemplateTemplateParam<T> t) {
|
|
return t.t;
|
|
}
|
|
|
|
/*
|
|
# template class
|
|
*/
|
|
|
|
template<class BASE=Base, class T=int, int N=10>
|
|
// OK, can derive from template.
|
|
class TemplateClass : public BASE {
|
|
public:
|
|
|
|
T t;
|
|
T ts[N];
|
|
|
|
TemplateClass(){callStack.push_back("TemplateClass::TemplateClass()");}
|
|
|
|
// BAD: what is T = string?
|
|
//TemplateClass() t(0.0){callStack.push_back("TemplateClass::TemplateClass()");}
|
|
|
|
TemplateClass(T t): t(t){callStack.push_back("TemplateClass::TemplateClass(T)");}
|
|
|
|
void method() {
|
|
callStack.push_back("TemplateClass::method()");
|
|
}
|
|
|
|
void methodDefinedOutside();
|
|
|
|
T method(T){callStack.push_back("TemplateClass::method(T)");}
|
|
|
|
// OK:
|
|
template<class C=int>
|
|
void methodTemplate() {
|
|
callStack.push_back("TemplateClass::methodTemplate()");
|
|
}
|
|
|
|
static const int sci = 0;
|
|
|
|
// BAD: impossible to define?
|
|
//static const TemplateClass<T,N>;
|
|
|
|
class Nested {
|
|
public:
|
|
T t;
|
|
};
|
|
|
|
int getIPrivate(){return iPrivate;}
|
|
|
|
private:
|
|
|
|
int iPrivate;
|
|
};
|
|
|
|
// This is exactly the same the TemplateClass with fixed T and N.
|
|
class TemplateFixed : TemplateClass<Base,int,10> {};
|
|
|
|
// OK:
|
|
class TemplatedNestedOut : TemplateClass<Base,int,10>::Nested {};
|
|
|
|
//template virtual
|
|
|
|
template<class T=int>
|
|
class TemplateAbstract {
|
|
virtual T virtualMethod(){return 1;}
|
|
virtual T pureVirtualMethod() = 0;
|
|
};
|
|
|
|
class TemplateAbstractDerived : public TemplateAbstract<int> {
|
|
virtual int virtualMethod(){return 1;}
|
|
virtual int pureVirtualMethod(){return 1;}
|
|
};
|
|
|
|
// C++11
|
|
template<class BASE, class T, int N>
|
|
void TemplateClass<BASE,T,N>::methodDefinedOutside() {
|
|
callStack.push_back("TemplateClass::methodDefinedOutside()");
|
|
}
|
|
|
|
#if __cplusplus >= 201103L
|
|
// # template specialization
|
|
|
|
// Specialization of function for case 12 only.
|
|
template<>
|
|
void TemplateClass<Base,int,11>::methodDefinedOutside() {
|
|
callStack.push_back("TemplateClass<Base,int,11>::methodDefinedOutside()");
|
|
// ERROR: T undeclared on specialiation
|
|
//T t;
|
|
}
|
|
|
|
// ERROR: case 11 was already defined on the spcecialization of methodDefinedOutside 11.
|
|
//template<> class TemplateClass<Base,int,11> {};
|
|
|
|
|
|
// Specialization of entire class from now on, a completely new class is created in case 12.
|
|
template<> class TemplateClass<Base,int,12> {
|
|
public:
|
|
|
|
void newMethod() {
|
|
callStack.push_back("TemplateClass<Base,int,12>::newMethod()");
|
|
}
|
|
};
|
|
|
|
// ERROR: case 12 class, created in class template specialization
|
|
// does not contain such a function
|
|
//template<>
|
|
//void TemplateClass<Base,int,12>::methodDefinedOutside(){}
|
|
#endif
|
|
|
|
//typename keyword qualifier
|
|
|
|
struct HasIMember {
|
|
static int i;
|
|
};
|
|
|
|
struct HasIType {
|
|
typedef int i;
|
|
};
|
|
|
|
struct HasIFunction {
|
|
int i() { return 1; }
|
|
};
|
|
|
|
struct HasITemplate {
|
|
template<int N> int i() { return N; }
|
|
};
|
|
|
|
/*
|
|
This function could do two things:
|
|
|
|
- multiplication of two values: `HAS_I::i` and `i`
|
|
- declartion of a `i` pointer of type `HAS_I::i`
|
|
|
|
The only way the compiler can differentiate between both, is knowing beforehand if `HAS_I::i`
|
|
is a type or a value.
|
|
|
|
But with templates, how can the compiler possibly know what `HAS_I::i` is going to be??
|
|
It could be both:
|
|
|
|
- a class that has a member `t` such as `HasIMember`.
|
|
|
|
- or another class that defines a type such as `HasIType`.
|
|
|
|
We must therefore help the compiler decide via the typename keyword!
|
|
*/
|
|
template<typename HAS_I>
|
|
void NoTypenameFunc() {
|
|
// Multiplication, or pointer declaration??
|
|
// `HAS_I::i` is both qualified (`::`) and dependant on `HAS_I`.
|
|
HAS_I::i * i;
|
|
}
|
|
|
|
template<typename HAS_I>
|
|
void TypenameFunc() {
|
|
typename HAS_I::i * i;
|
|
}
|
|
|
|
template<typename HAS_I>
|
|
void NoTypenameInTemplateFunc() {
|
|
// Even if here it clearly cannot be a value, only a type,
|
|
// we must still help the compiler parse it with `typename`.
|
|
//
|
|
// ERROR: this could never work, since it does not have the typename specifier
|
|
// and therefore always means a value for the compiler.
|
|
//std::vector<HAS_I::i> v;
|
|
}
|
|
|
|
template<typename HAS_I>
|
|
void TypenameInTemplateFunc() {
|
|
std::vector<typename HAS_I::i> v;
|
|
}
|
|
|
|
// Template keyword qualifier.
|
|
|
|
class TemplateQualifier {
|
|
public:
|
|
template<int N>
|
|
class Nested {
|
|
public:
|
|
int method() { return N; }
|
|
};
|
|
|
|
template<int N>
|
|
static int TemplateMethod() { return N; }
|
|
};
|
|
|
|
template<typename T>
|
|
void TemplateQualifierTest(TemplateQualifier tq, T t, T* tp) {
|
|
|
|
assert(tq.TemplateMethod<1>() == 1);
|
|
assert(tq.template TemplateMethod<1>() == 1);
|
|
|
|
// Template keyword is only needed for arguments with dependent type.
|
|
assert(tq.TemplateMethod<1>() == 1);
|
|
assert(tq.template TemplateMethod<1>() == 1);
|
|
|
|
//assert( t.TemplateMethod<1>());
|
|
assert(t.template TemplateMethod<1>() == 1);
|
|
|
|
//assert( tp TemplateMethod<1>() == 1)
|
|
assert(tp->template TemplateMethod<1>() == 1);
|
|
|
|
//assert( T::TemplateMethod<1>() == 1);
|
|
assert(T::template TemplateMethod<1>() == 1);
|
|
|
|
//typename T::Nested<1> n;
|
|
typename T::template Nested<1> n;
|
|
assert(n.method() == 1);
|
|
}
|
|
|
|
#if __cplusplus >= 201103L
|
|
// # variadic template
|
|
|
|
// Base case.
|
|
template <typename T>
|
|
T variadicSum(T t) { return(t); }
|
|
|
|
template <typename T, typename... P>
|
|
T variadicSum(T t, P... p) {
|
|
if (sizeof...(p)) {
|
|
t += variadicSum(p...);
|
|
}
|
|
return(t);
|
|
}
|
|
|
|
template <typename... Args>
|
|
std::size_t VariadicSizeof() {
|
|
return sizeof...(Args);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
#thread
|
|
*/
|
|
|
|
int nNsecs = 10;
|
|
int threadGlobal = 0;
|
|
int threadGlobalMutexed = 0;
|
|
std::mutex threadGlobalMutex;
|
|
std::thread::id lastThreadId;
|
|
std::set<std::thread::id> threadIds;
|
|
|
|
int threadGlobalEq0 = 0;
|
|
int threadGlobalMutexedEq0 = 0;
|
|
int threadChange = 0;
|
|
|
|
void threadFunc(int threadCountToSqrt) {
|
|
std::thread::id id = std::this_thread::get_id();
|
|
for (int i=0; i<threadCountToSqrt; i++)
|
|
for (int j=0; j<threadCountToSqrt; j++) {
|
|
if (lastThreadId != id) {
|
|
++threadChange;
|
|
//threadIds.insert(id);
|
|
lastThreadId = id;
|
|
}
|
|
|
|
// cout is not thread safe order gets mixed up.
|
|
//std::cout << id << " " << i << endl;
|
|
|
|
// If happens.
|
|
|
|
threadGlobal = 1;
|
|
if (threadGlobal == 0)
|
|
++threadGlobalEq0;
|
|
threadGlobal = 0;
|
|
|
|
// If never happens!
|
|
|
|
threadGlobalMutex.lock();
|
|
// if not available, wait
|
|
//threadGlobalMutex.try_lock();
|
|
// If not available, return!
|
|
threadGlobalMutexed = 1;
|
|
if (threadGlobalMutexed == 0)
|
|
++threadGlobalMutexedEq0;
|
|
threadGlobalMutexed = 0;
|
|
threadGlobalMutex.unlock();
|
|
|
|
}
|
|
std::this_thread::sleep_for (std::chrono::nanoseconds(nNsecs));
|
|
// Done, pass to another thread.
|
|
std::this_thread::yield();
|
|
}
|
|
|
|
#ifdef PROFILE
|
|
const static int nProfRuns = 100000000;
|
|
|
|
// Only the loop. Discount this from every other profile run.
|
|
void loopOnlyProf(int n) {
|
|
int i;
|
|
for (i=0; i<n; i++);
|
|
}
|
|
|
|
void whileOnlyProf(int n) {
|
|
int i = 0;
|
|
while (i < n)
|
|
++i;
|
|
}
|
|
|
|
void intAssignProf(int n) {
|
|
int i,j;
|
|
for (i=0; i<n; i++)
|
|
j=1;
|
|
}
|
|
|
|
void doNothing(){}
|
|
|
|
void funcCallProf(int n) {
|
|
int i;
|
|
for (i=0; i<n; i++)
|
|
doNothing();
|
|
}
|
|
|
|
static inline void inlineDoNothing(){}
|
|
|
|
void inlineFuncCallProf(int n) {
|
|
int i;
|
|
for (i=0; i<n; i++)
|
|
inlineDoNothing();
|
|
}
|
|
|
|
void intSumProf(int n) {
|
|
int i, j = 0;
|
|
for (i=0; i<n; i++)
|
|
j = j + 0;
|
|
}
|
|
|
|
void intSubProf(int n) {
|
|
int i, j = 0;
|
|
for (i=n; i>0; i--);
|
|
j = j - 0;
|
|
}
|
|
|
|
void intMultProf(int n) {
|
|
int i, j = 1;
|
|
for (i=0; i<n; i++)
|
|
j = j * 1;
|
|
}
|
|
|
|
void intDivProf(int n) {
|
|
int i, j = 1;
|
|
for (i=0; i<n; i++)
|
|
j = j / 1;
|
|
}
|
|
|
|
void floatSumProf(int n) {
|
|
float f;
|
|
int i;
|
|
for (i=0; i<n; i++)
|
|
f = f + 0.0;
|
|
}
|
|
|
|
void floatSubProf(int n) {
|
|
float f;
|
|
int i;
|
|
for (i=0; i<n; i++)
|
|
f = f - 0.0;
|
|
}
|
|
|
|
void floatMultProf(int n) {
|
|
int i;
|
|
float j;
|
|
for (i=0; i<n; i++)
|
|
j = j * 1.0;
|
|
}
|
|
|
|
void floatDivProf(int n) {
|
|
int i;
|
|
float j;
|
|
for (i=0; i<n; i++)
|
|
j = j / 1.0;
|
|
}
|
|
|
|
void putsProf(int n) {
|
|
int i;
|
|
for (i = 0; i < n; ++i)
|
|
puts("");
|
|
}
|
|
|
|
void stack1bProf(int n) {
|
|
int is[1];
|
|
int i;
|
|
for (i = 0; i < n; ++i)
|
|
int is[1];
|
|
}
|
|
|
|
void stack1kbProf(int n) {
|
|
int is[1];
|
|
int i;
|
|
for (i = 0; i < n; ++i) {
|
|
int is[0x800];
|
|
}
|
|
}
|
|
|
|
void stack1mbProf(int n) {
|
|
int is[1];
|
|
int i;
|
|
for (i = 0; i < n; ++i)
|
|
int is[0xF0000];
|
|
}
|
|
|
|
void heapMalloc1bProf(int n) {
|
|
char* cp;
|
|
int i;
|
|
for (i = 0; i < n; ++i) {
|
|
cp = (char*) malloc(sizeof(char) * 1);
|
|
free(cp);
|
|
}
|
|
}
|
|
|
|
void heapMalloc1kbProf(int n) {
|
|
char* cp;
|
|
int i;
|
|
for (i = 0; i < n; ++i) {
|
|
cp = (char*) malloc(sizeof(char) * 0x800);
|
|
free(cp);
|
|
}
|
|
}
|
|
|
|
void heapMalloc1mbProf(int n) {
|
|
char* cp;
|
|
int i;
|
|
for (i = 0; i < n; ++i) {
|
|
cp = (char*) malloc(sizeof(char) * 0xF0000);
|
|
free(cp);
|
|
}
|
|
}
|
|
|
|
void heapNew1bProf(int n) {
|
|
char* cp;
|
|
int i;
|
|
for (i = 0; i < n; ++i) {
|
|
cp = new char[1];
|
|
delete[] cp;
|
|
}
|
|
}
|
|
|
|
void heapNew1kbProf(int n) {
|
|
char* cp;
|
|
int i;
|
|
for (i = 0; i < n; ++i) {
|
|
cp = new char[0x800];
|
|
delete[] cp;
|
|
}
|
|
}
|
|
|
|
void heapNew1mbProf(int n) {
|
|
char* cp;
|
|
int i;
|
|
for (i = 0; i < n; ++i) {
|
|
cp = new char[0xF0000];
|
|
delete[] cp;
|
|
}
|
|
}
|
|
|
|
class BaseProf {
|
|
public:
|
|
virtual void virtualMethod(){}
|
|
};
|
|
|
|
class ClassProf {
|
|
public:
|
|
void method(){}
|
|
virtual void virtualMethod(){}
|
|
};
|
|
|
|
void methodCallProf(int n) {
|
|
ClassProf c;
|
|
int i;
|
|
for (i = 0; i < n; ++i) {
|
|
c.method();
|
|
}
|
|
}
|
|
|
|
void virtualMethodCallProf(int n) {
|
|
ClassProf c;
|
|
int i;
|
|
for (i = 0; i < n; ++i) {
|
|
c.virtualMethod();
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
//constexpr
|
|
|
|
int not_constexpr_func() {
|
|
return 1;
|
|
}
|
|
|
|
constexpr int constexpr_func(int i) {
|
|
return i;
|
|
}
|
|
|
|
/*
|
|
C++11 specifies that the body of a constexrp function must contain a single return statement.
|
|
|
|
Otherwise, it would be too much work for the compiler to do.
|
|
|
|
<http://stackoverflow.com/questions/3226211/why-is-it-ill-formed-to-have-multi-line-constexpr-functions>
|
|
*/
|
|
/*
|
|
constexpr int constexpr_func_multi_statement(int i) {
|
|
int j;
|
|
return i;
|
|
}
|
|
*/
|
|
|
|
constexpr int ConstexprFactorial(int n) {
|
|
return (n == 1) ? 1 : n * ConstexprFactorial(n - 1);
|
|
}
|
|
|
|
|
|
/**
|
|
ERROR: the compiler ensures that the function is constexpr,
|
|
so this does not compile.
|
|
*/
|
|
/*
|
|
int constexpr constexpr_func_bad(){
|
|
return std::time();
|
|
}
|
|
*/
|
|
|
|
//string
|
|
|
|
std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
|
|
std::stringstream ss(s);
|
|
std::string item;
|
|
while (std::getline(ss, item, delim)) {
|
|
elems.push_back(item);
|
|
}
|
|
return elems;
|
|
}
|
|
|
|
std::vector<std::string> split(const std::string &s, char delim) {
|
|
std::vector<std::string> elems;
|
|
split(s, delim, elems);
|
|
return elems;
|
|
}
|
|
|
|
//File IO
|
|
|
|
void ios_write_fail(std::string path) {
|
|
throw std::ios_base::failure("Error: Could not write to file: " + path);
|
|
}
|
|
|
|
void ios_read_fail(std::string path) {
|
|
throw std::ios_base::failure("Error: Could not read file: " + path);
|
|
}
|
|
|
|
/**
|
|
Read entire file into a string at once.
|
|
*/
|
|
void read_file(std::ifstream &ifs, std::string &data_read) {
|
|
ifs.seekg(0, std::ios::end);
|
|
size_t size = ifs.tellg();
|
|
data_read.resize(size);
|
|
ifs.seekg(0);
|
|
ifs.read(&data_read[0], size);
|
|
ifs.close();
|
|
}
|
|
|
|
//to_str
|
|
|
|
template <class K, class V>
|
|
std::string map_to_str(std::map<K,V> map) {
|
|
std::stringstream result;
|
|
for (auto& pair : map) {
|
|
result << pair.first << ":" << pair.second << ", ";
|
|
}
|
|
return result.str();
|
|
}
|
|
|
|
//attributes
|
|
|
|
void noreturn_func [[ noreturn ]] () { throw 1; }
|
|
|
|
//Misc
|
|
|
|
bool odd(int i){ return (i % 2) == 1; }
|
|
|
|
int bind2ndTarget(int i, int j) {
|
|
return i + j;
|
|
}
|
|
|
|
class ClassWithTypedef {
|
|
public:
|
|
typedef int typedefPublic;
|
|
private:
|
|
typedef int typedefPrivate;
|
|
};
|
|
|
|
/*
|
|
# main
|
|
|
|
# main signature
|
|
|
|
- http://stackoverflow.com/questions/4207134/what-is-the-proper-declaration-of-main
|
|
- http://stackoverflow.com/questions/1621574/can-the-arguments-of-mains-signature-in-c-have-the-unsiged-and-const-qualifie
|
|
|
|
Much like in C, only:
|
|
|
|
int main();
|
|
int main(int, char*[]);
|
|
|
|
are required to work, but more likely work as well.
|
|
|
|
# Call main from the program
|
|
|
|
In C++, cannot be called from anywherelse in the program, including recursively:
|
|
http://stackoverflow.com/questions/2128321/can-main-function-call-itself-in-c
|
|
|
|
This restriction does not seem to exist in C.
|
|
*/
|
|
int main(int argc, char **argv) {
|
|
|
|
// # Scope
|
|
{
|
|
/*
|
|
# typedef struct
|
|
|
|
# typedef class
|
|
|
|
# struct keyword omission
|
|
|
|
Unlike in C, struct tags and variable names live in the same namespace.
|
|
|
|
In C++ you can normally omit `struct`
|
|
`struct s` is called an #elaborated-type-specifier.
|
|
<http://stackoverflow.com/a/14261176/895245>
|
|
|
|
But if there is ambiguity, the only way to refer to the struct
|
|
is by appending `struct`.
|
|
*/
|
|
{
|
|
int s = 1;
|
|
struct s {int i;};
|
|
assert(s == 1);
|
|
// ERROR
|
|
//s t = {1};
|
|
struct s t = {1};
|
|
assert(t.i == 1);
|
|
|
|
int c = 1;
|
|
class c { public: int i; };
|
|
assert(c == 1);
|
|
// ERROR
|
|
//c u = {1};
|
|
class c u = {1};
|
|
assert(u.i == 1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
# assign operator
|
|
|
|
Unlike in C, C++ assign operator returns lvalues!
|
|
|
|
TODO rationale. Related to return refs from functions?
|
|
*/
|
|
{
|
|
int i = 0, j = 1, k = 2;
|
|
|
|
(i = j) = k;
|
|
/*^^^^^^^^^
|
|
|
|
|
returns a lvalue pointing to `i`
|
|
|
|
Therefore is the same as:
|
|
|
|
i = j;
|
|
i = k;
|
|
*/
|
|
|
|
assert(i == 2);
|
|
assert(j == 1);
|
|
assert(k == 2);
|
|
|
|
// ERROR: as in C, most other operators do not return lvalues
|
|
//(i + j) = k;
|
|
}
|
|
|
|
/*
|
|
# bool
|
|
|
|
in C++, unlike in C, bool is part of the language.
|
|
*/
|
|
{
|
|
bool b;
|
|
|
|
b = true;
|
|
b = 1;
|
|
|
|
if (true)
|
|
{
|
|
assert(true);
|
|
}
|
|
if (false)
|
|
{
|
|
assert(false);
|
|
}
|
|
|
|
{
|
|
std::stringstream oss;
|
|
oss << true;
|
|
assert(oss.str() == "1");
|
|
}
|
|
|
|
{
|
|
std::stringstream oss;
|
|
oss << false;
|
|
assert(oss.str() == "0");
|
|
}
|
|
|
|
}
|
|
|
|
// # unsigned
|
|
{
|
|
unsigned int ui = -1;
|
|
int i = 1;
|
|
//if (ui<i)
|
|
// WARN: in c, no WARN
|
|
}
|
|
|
|
/*
|
|
# constant expressions at compile time
|
|
|
|
<http://en.cppreference.com/w/cpp/language/constant_expression>
|
|
|
|
Constant expressions at compile time can be used in contexts where non constants cannont:
|
|
|
|
- array lengths at array declaration
|
|
- numeric template parameters
|
|
|
|
The compiler is able to determine which expressions are constant recursively.
|
|
|
|
Note that variables with the keyword `const` may or may not be constant expressions.
|
|
depending on how they are initialized.
|
|
|
|
Those defined with the keyword constexpr however are ensured by the compiler to be
|
|
compile time constants.
|
|
*/
|
|
|
|
/*
|
|
Get array length, find array length: <http://stackoverflow.com/questions/4108313/how-do-i-find-the-length-of-an-array>
|
|
|
|
Besides the C sizeof method which does not work for pointers and has lots of duplication, C++ offers:
|
|
*/
|
|
{
|
|
// Vector class. Has overhead, but probably the best option given its flexibility.
|
|
|
|
// #array class. No overhead. Fixed size. Template based.
|
|
{
|
|
// WARN: double brackets required TODO why
|
|
//std::array<int, 3> a{0, 1, 2};
|
|
|
|
std::array<int, 3> a{{0, 1, 2}};
|
|
assert(a.size() == 3);
|
|
}
|
|
|
|
// Method which I don't understand.
|
|
{
|
|
//template<class T, size_t N>
|
|
//size_t size(T (&)[N]) { return N; }
|
|
}
|
|
}
|
|
|
|
/*
|
|
# array size from variables
|
|
|
|
In C++, any constant expression at compile time can be used as an array size.
|
|
|
|
This includes in particular intetegers declared as `const` and initialized by a constant expression,
|
|
and in C++11 all `constexpr` variables.
|
|
*/
|
|
{
|
|
std::srand(time(NULL));
|
|
|
|
{
|
|
int i = 1;
|
|
i = std::rand();
|
|
// ERROR: the size would not be fixed
|
|
//int is[i];
|
|
}
|
|
|
|
{
|
|
// Compile time constant since the literal 1 is a constant expression.
|
|
const int ci = 1;
|
|
// Cannot do that, so the size is fixed!
|
|
//ci = 2;
|
|
int is[ci];
|
|
}
|
|
|
|
// ERROR: the compiler is able to see that ci is not a compile time constant
|
|
{
|
|
const int ci = std::rand();
|
|
//int is[ci];
|
|
}
|
|
}
|
|
|
|
/*
|
|
# const keyword
|
|
|
|
There are differences between the `const` keyword in C and C++!
|
|
|
|
Also, in C++ const can be used to qualify methods.
|
|
|
|
<http://stackoverflow.com/questions/8908071/const-correctness-in-c-vs-c>
|
|
*/
|
|
{
|
|
/*
|
|
In C++, consts cannot be changed not even through pointers.
|
|
|
|
C this is only a warning, and allows us to change ic.
|
|
*/
|
|
{
|
|
const int i = 2;
|
|
//int* ip = i;
|
|
}
|
|
|
|
//unlike for constexpr, const does not need to have value define at compile time
|
|
{
|
|
const int i = std::time(NULL);
|
|
}
|
|
|
|
//consts must be initialized at declaration because they cannot be modified after.
|
|
{
|
|
//const int i;
|
|
// ERROR i not initialized
|
|
|
|
// ERROR uninitialized
|
|
//int * const ipc;
|
|
|
|
// OK: we can change which object it points to
|
|
{
|
|
int i = 0;
|
|
int j = 0;
|
|
int const * icp;
|
|
icp = &i;
|
|
icp = &j;
|
|
// ERROR
|
|
//*icp = 1;
|
|
}
|
|
|
|
// C is initialized by the constructor
|
|
// so it is OK to do this unlike for base types
|
|
const Class c;
|
|
}
|
|
|
|
// Const for classes.
|
|
{
|
|
const Class c;
|
|
|
|
// Cannot reassign:
|
|
|
|
//cc = Class();
|
|
|
|
// Cannot assign members:
|
|
|
|
//cc.i = 1;
|
|
|
|
// Can create const refs to:
|
|
|
|
const int& cia = c.i;
|
|
|
|
// Cannot create non const refs:
|
|
|
|
//int& ia = cc.i;
|
|
|
|
/*
|
|
Can only call const methods,
|
|
because a non const method could change the object.
|
|
|
|
Therefore, *BE CONST OBSESSIVE!* mark as const every method that does not change the object!
|
|
*/
|
|
{
|
|
//c.method();
|
|
c.constMethod();
|
|
}
|
|
}
|
|
}
|
|
|
|
#if __cplusplus >= 201103L
|
|
|
|
/*
|
|
# constexpr
|
|
|
|
C++11 keyword.
|
|
|
|
`const` variables can either be compile time constants or not.
|
|
|
|
The compiler is able to decide that at compile time, but it may be hard for human
|
|
readers to predict if a given variable is a constexpr of not.
|
|
|
|
Using the constexpr keyword however makes the compiler ensure that the variables are constant expressions,
|
|
so that the compile time constantness is more explicit.
|
|
|
|
Two uses:
|
|
|
|
- variables
|
|
|
|
Means that the value of an expression is known at compile time.
|
|
|
|
- functions
|
|
|
|
The value returned by constexpr functions is known to be a compile time constant.
|
|
|
|
The compiler enforces this by inspecting the function.
|
|
*/
|
|
{
|
|
// OK: built-in operations that take constexprs return a constexpr
|
|
{
|
|
constexpr int i = 1 + 1;
|
|
}
|
|
|
|
// OK: it is a constexpr
|
|
{
|
|
constexpr int i = 0;
|
|
constexpr int i2 = i;
|
|
}
|
|
|
|
// OK: the compiler sees that a const initialized by a constexpr is also a constexpr.
|
|
{
|
|
const int i = 0;
|
|
constexpr int i2 = i;
|
|
}
|
|
|
|
// ERROR: for non built-in operators, only constexpr functions can be used.
|
|
{
|
|
//constexpr int i = not_constexpr_func();
|
|
}
|
|
|
|
// constexpr functions only work if all their arguments are constexprs.
|
|
{
|
|
{ constexpr int i = constexpr_func(1); }
|
|
//{ constexpr int i = constexpr_func(std::time(NULL)); }
|
|
}
|
|
|
|
// Recursive functions can be constexpr, as long as they fit into one line.
|
|
{
|
|
constexpr int i = ConstexprFactorial(3);
|
|
assert(i == 6);
|
|
}
|
|
|
|
// ERROR: the compiler sees that this is not a constexpr.
|
|
// Avoid relying on this execept for legacy code: always initialize a constexpr from constexprs!
|
|
{
|
|
const int i = std::time(NULL);
|
|
//constexpr int i2 = i + 1;
|
|
}
|
|
|
|
// ERROR: it is not a constexpr
|
|
{
|
|
int i = 0;
|
|
//i = std::time(NULL);
|
|
// We could change i at any time!
|
|
//constexpr int i2 = i + 1;
|
|
}
|
|
|
|
// ERROR: constexprs cannot be modified after initialization
|
|
{
|
|
constexpr int i = 0;
|
|
//i = 1;
|
|
}
|
|
|
|
// WARN: unitialized constexpr
|
|
{
|
|
//constexpr int i;
|
|
}
|
|
|
|
/*
|
|
cannot have constexpr to complex types
|
|
|
|
TODO rationale
|
|
*/
|
|
{
|
|
//constexpr std::string s = "abc";
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
#if __cplusplus >= 201103L
|
|
|
|
/*
|
|
# nullptr
|
|
|
|
C++11 keyword.
|
|
|
|
Better alternative to `0` and `NULL` ugliness:
|
|
|
|
<http://stackoverflow.com/questions/1282295/what-exactly-is-nullptr>
|
|
|
|
# nullptr_t
|
|
|
|
Type of nullptr.
|
|
*/
|
|
{
|
|
// No address can be nullptr
|
|
{
|
|
std::nullptr_t p = nullptr;
|
|
int i;
|
|
//assert(&i != p);
|
|
//gcc 4.7 warning: &i will never be null. Smart.
|
|
}
|
|
|
|
// It is possible to convert NULL and 0 to nullptr_t.
|
|
{
|
|
std::nullptr_t p;
|
|
p = NULL;
|
|
p = 0;
|
|
}
|
|
|
|
/*
|
|
It is not possible to convert nullptr_t to NULL and 0
|
|
|
|
This allows to overload a function for both pointer and integer.
|
|
|
|
In that case, passing it a `0` would always select the integer version.
|
|
*/
|
|
{
|
|
//int i = nullptr;
|
|
}
|
|
|
|
// Unlike in NULL, the size of nullptr_t is fixed.
|
|
{
|
|
assert(sizeof(std::nullptr_t) == sizeof(void*));
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/*
|
|
# &
|
|
|
|
# References.
|
|
|
|
Basically aliases, similar to `int* const` poinsters or java objects.
|
|
|
|
Useful only for function arguments or / return values. In that case the pros are:
|
|
|
|
- callers that have an object don't need to dereference it with `&`
|
|
|
|
- it is self documenting on the code that the given reference always points to the same thing
|
|
either to modify it or to pass it efficiently without copy.
|
|
|
|
The cons are:
|
|
|
|
- callers don't know without looking at the signature if they are passing references or copies,
|
|
and wether they should expect that it is possible that the functio modifies their object.
|
|
|
|
Just like for pointers, you have to watch scope. If the original object dies,
|
|
you get a dangling reference
|
|
|
|
- <http://stackoverflow.com/questions/752658/is-the-practice-of-returning-a-c-reference-variable-evil>
|
|
- <http://stackoverflow.com/questions/7058339/c-when-to-use-references-vs-pointers>
|
|
*/
|
|
{
|
|
// Basic usage as function parameters that are return values.
|
|
{
|
|
int i = 0;
|
|
byref(i);
|
|
assert(i == 1);
|
|
}
|
|
|
|
/*
|
|
References have the same address of the variables.
|
|
|
|
Therefore:
|
|
|
|
- if declared inside the same function as the value, no extra memory / dereferencing
|
|
needs to be used for references, the compiler can figure everything out at compile time.
|
|
|
|
- if declared as function arguments, references may be implemented as implicit pointers passing,
|
|
sharing therefore the disadvantages of pointers.
|
|
|
|
Therefore, if you want to be sure of efficiency, pass built-in types by value and not by reference.
|
|
*/
|
|
{
|
|
// They have the same address.
|
|
{
|
|
int i = 0;
|
|
int& ia = i;
|
|
ia = 1;
|
|
assert(i == 1);
|
|
assert(&i == &ia);
|
|
}
|
|
|
|
/*
|
|
For the same reason, it is possible to initialize a reference from another reference.
|
|
*/
|
|
{
|
|
int i = 0;
|
|
int& ia = i;
|
|
int& ia2 = ia;
|
|
ia2 = 2;
|
|
assert(i == 2);
|
|
}
|
|
}
|
|
|
|
/*
|
|
ERROR: Must not initialize non-const ref with a rvalue.
|
|
|
|
Can however do that for const references.
|
|
|
|
The same goes for function parameters.
|
|
*/
|
|
{
|
|
//int& ia = 0;
|
|
//std::string& s = getString();
|
|
const std::string& s = getString();
|
|
//byref(1);
|
|
}
|
|
|
|
/*
|
|
ERROR: references must be initialized imediatelly
|
|
otherwise, how can they be initalized in the future?
|
|
|
|
For references in constructors, they must be initialized at the initialization list.
|
|
*/
|
|
{
|
|
//int& ia;
|
|
}
|
|
|
|
/*
|
|
It is possible to get references from pointers.
|
|
*/
|
|
{
|
|
int i = 0;
|
|
int* ip = &i;
|
|
int& ia = *ip;
|
|
ia = 1;
|
|
assert(i == 1);
|
|
|
|
// ERROR: & must get a variable/dereferenced pointer, not pointers themselves!
|
|
{
|
|
//int& ia = &i;
|
|
}
|
|
}
|
|
|
|
/* It is not possible to make an array of references. */
|
|
{
|
|
int i = 1;
|
|
int j = 2;
|
|
|
|
// ERROR: array of references forbidden
|
|
//int& is[2] = {i,i};
|
|
}
|
|
|
|
/*
|
|
# const references
|
|
|
|
References that do not allow one to modify the value of the variable.
|
|
*/
|
|
{
|
|
|
|
//it is possible to make a const reference from a non-const object
|
|
{
|
|
int i = 1;
|
|
const int& cia = i;
|
|
|
|
// ERROR: const references cannot be modified
|
|
//cia = 2;
|
|
}
|
|
|
|
//it is possible to make a const reference form a const object
|
|
{
|
|
const int ci = 1;
|
|
const int& cia = ci;
|
|
|
|
// ERROR: const references cannot be modified
|
|
//cia = 2;
|
|
}
|
|
|
|
/*
|
|
The rules imposed by the compiler make sure that it is hard or impossible to cheat references by mistake.
|
|
*/
|
|
{
|
|
int i = 1;
|
|
const int& cia = i;
|
|
|
|
// ERROR: invalid conversion
|
|
//int& ia = cia;
|
|
|
|
// ERROR: invalid conversion
|
|
//int *ip = &cia;
|
|
}
|
|
|
|
/*
|
|
const references can be initialized by rvalues!
|
|
|
|
This cannot be wrong since they cannot be modified,
|
|
so it is not possible to modify the non-existent variable.
|
|
|
|
In this case what happens is that a simple copy takes place.
|
|
|
|
One case in which this rule is very important is parameter passing to functions.
|
|
|
|
For exapmle, the following would be bad:
|
|
|
|
void f(int& i) {
|
|
i++;
|
|
}
|
|
|
|
...
|
|
|
|
f(1);
|
|
//does not compile
|
|
|
|
and is impossible, but:
|
|
|
|
void f(const int& i) {
|
|
//i++;
|
|
//impossible
|
|
}
|
|
|
|
f(1);
|
|
|
|
is ok, since it is impossible to change i in the function if it is const
|
|
*/
|
|
{
|
|
//initialization from a literal
|
|
{
|
|
const int& i = 1;
|
|
assert(i == 1);
|
|
}
|
|
|
|
/*
|
|
Initialization from a non-reference function return.
|
|
|
|
Functions that return references return lvalues,
|
|
so an example with such a function would not be meaningful.
|
|
*/
|
|
{
|
|
const int& i = getInt();
|
|
assert(i == 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
# reference to pointer
|
|
|
|
like for other variable, references can be made to pointer variables.
|
|
*/
|
|
{
|
|
{
|
|
int i = 0;
|
|
int j = 1;
|
|
int *ip = &i;
|
|
int *jp = &j;
|
|
int*& ipa = ip;
|
|
int*& jpa = jp;
|
|
|
|
jpa = ip;
|
|
//now `jp` is the same as `ip`!
|
|
|
|
*jp = 2;
|
|
assert(i == 2);
|
|
//therefore modifying what `jp` points to modifies `i`!
|
|
|
|
// ERROR: makes no sense: cannot have a pointer to `int&`
|
|
//int&* ipaBad = ip;
|
|
|
|
// ERROR: `&i` is an rvalue. Cannot initialize a non const reference to it.
|
|
//int&* ipaBad = &i;
|
|
}
|
|
|
|
/*
|
|
# reference to pointer and const
|
|
|
|
Just like for pointers to pointers in C, the rules prevent `const` variables
|
|
from being modified.
|
|
*/
|
|
{
|
|
/*
|
|
Obviously, cannot remove const qualifiers, or it would be easy to modify constants.
|
|
*/
|
|
{
|
|
const int c = 0;
|
|
const int *ip = &c;
|
|
//int *&ipa = ip;
|
|
//int *ipa = ip;
|
|
//*ipa = 1;
|
|
}
|
|
|
|
/*
|
|
`const int*& = int*` initialization fails for the same reason that `const int* = (int*)` fails in C:
|
|
this would allow for constant modification.
|
|
*/
|
|
{
|
|
//If (1) were possible below, then it would be possible to change the value of the constant c.
|
|
{
|
|
/*
|
|
int *ip = NULL;
|
|
const int*& ipa = ip; // (1) THIS is not possible
|
|
const int c = 0;
|
|
ipa = &c; // OK because ipa is const. `ip` points to `c`
|
|
*ip = 1; // OK because ip is not const
|
|
*/
|
|
}
|
|
|
|
/*
|
|
This is different without the reference, because in this case
|
|
it would not be possible to change the const variable.
|
|
|
|
Just like in C, the issues only show up in pointer dimensions > 1,
|
|
and the reference behaves like a pointer.
|
|
*/
|
|
{
|
|
int *ip = NULL;
|
|
const int* ipa = ip; // (1) THIS is ok without the reference, a new pointer is created
|
|
const int c = 0;
|
|
ipa = &c; // OK because ipa is const. ip still points to NULL
|
|
//*ip = 1; // does not change the constant, ip still points to NULL
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
What to do if:
|
|
|
|
- a function modifies what pointers point to but not the object pointed to.
|
|
|
|
It therefore takes
|
|
|
|
- we want to pass pointers to that function, modify what they point to,
|
|
and then outside of the function modify the object being pointed to?
|
|
|
|
Is this a valid use case for `const_cast`?
|
|
*/
|
|
{
|
|
//the motivation: functions
|
|
{
|
|
int i = 0;
|
|
int j = 1;
|
|
int *ip = &i;
|
|
int *jp = &j;
|
|
|
|
//const int *ip = &i;
|
|
//const int *jp = &j;
|
|
//if those were const, the function call would work,
|
|
//but not the `*ip = 2`;
|
|
|
|
//bypointerConst(ip, jp);
|
|
//cannot initialize `const int*&` with `int*&`.
|
|
|
|
*ip = 2;
|
|
//assert(j == 2);
|
|
}
|
|
|
|
//same problem simplified without functions
|
|
{
|
|
int i = 0;
|
|
int *ip = &i;
|
|
|
|
//int*& ipa = ip;
|
|
//possible
|
|
|
|
//const int*& ipa = ip;
|
|
//TODO why is this not possible
|
|
}
|
|
|
|
//but this is possible?
|
|
{
|
|
int i = 0;
|
|
const int& ia = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
Single line initialization syntax.
|
|
|
|
Like the pointer symbol `*`, the reference symbol `&` needs to be duplicated for each new reference variable.
|
|
*/
|
|
{
|
|
//ok: both ia and ja are references
|
|
{
|
|
int i = 1;
|
|
int j = 2;
|
|
int &ia = i, &ja = j;
|
|
|
|
ia = -1;
|
|
ja = -2;
|
|
|
|
assert(i == -1);
|
|
assert(j == -2);
|
|
}
|
|
|
|
//ko: ja is a new int, not a reference
|
|
{
|
|
int i = 1;
|
|
int j = 2;
|
|
int& ia = i, ja = j;
|
|
|
|
ia = -1;
|
|
ja = -2;
|
|
|
|
assert(i == -1);
|
|
assert(j == 2);
|
|
}
|
|
|
|
//with references to pointers it looks like this
|
|
{
|
|
int i = 0;
|
|
int j = 1;
|
|
int *ip = &i;
|
|
int *jp = &j;
|
|
|
|
int *& ipa = ip, *& jpa = jp;
|
|
|
|
jpa = ip;
|
|
*jp = 2;
|
|
assert(i == 2);
|
|
}
|
|
}
|
|
|
|
/*
|
|
# return reference from function
|
|
|
|
Just like when returning pointers from functions,
|
|
one must take care not to return dangling references.
|
|
*/
|
|
{
|
|
/*
|
|
One simple case in which lifetime is simple to guarantee is
|
|
returning members from objects which the callee owns. For example:
|
|
*/
|
|
{
|
|
Base b;
|
|
int& ia = b.getRefIPublic();
|
|
ia = 0;
|
|
assert(b.iPublic == 0);
|
|
ia = 1;
|
|
assert(b.iPublic == 1);
|
|
}
|
|
|
|
//you can modify a private if you non const reference to it
|
|
{
|
|
Base b;
|
|
int& ia = b.getPrivateRef();
|
|
ia = 0;
|
|
assert(b.getPrivateRef() == 0);
|
|
ia = 1;
|
|
assert(b.getPrivateRef() == 1);
|
|
}
|
|
|
|
//if the reference is const it does not work anymore
|
|
{
|
|
Base b;
|
|
|
|
{
|
|
const int& ia = b.getPrivateConstRef();
|
|
//ia = 1;
|
|
}
|
|
|
|
// ERROR: invalid initialization
|
|
{
|
|
//int& ia = b.getPrivateConstRef();
|
|
}
|
|
}
|
|
|
|
/*
|
|
In C, all functions return rvalues,
|
|
although if a function returns a pointer and that pointer is dereferenced it becomes an lvalue,
|
|
so the following works:
|
|
|
|
(*ret_int_ptr()) = 1;
|
|
|
|
In C++, there is an exception: all functions that return references return lvalues directly.
|
|
*/
|
|
{
|
|
int i = 0;
|
|
(getIntRef(i)) = 2;
|
|
assert(i == 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
#if __cplusplus >= 201103L
|
|
|
|
/*
|
|
# auto
|
|
|
|
C++11 keyword
|
|
|
|
Completelly differs in meaning with the useless C `auto` keyword.
|
|
|
|
Variable type is infered based on return value of initialization.
|
|
|
|
Reduces code duplication, since it allows us to not write explicitly types everywhere.
|
|
|
|
Major application: create an iterator without speficying container type.
|
|
*/
|
|
{
|
|
// Basic usage.
|
|
{
|
|
//the compiler infers the type of i from the initialization.
|
|
auto i = 1;
|
|
}
|
|
|
|
// Reference.
|
|
{
|
|
int i = 1;
|
|
auto& ai = i;
|
|
ai = 2;
|
|
assert(i == 2);
|
|
}
|
|
|
|
// ERROR: must initialize immediately. How could the compiler deduce type otherwise?
|
|
{
|
|
//auto i;
|
|
//i = 1;
|
|
}
|
|
|
|
// If initialized from reference, discards the reference, while decltype keeps it.
|
|
{
|
|
int i = 0;
|
|
int& ir = i;
|
|
auto ir2 = ir;
|
|
ir2 = 1;
|
|
assert(i == 0);
|
|
}
|
|
|
|
// Array. Seems not.
|
|
{
|
|
//auto is[]{1, 0};
|
|
}
|
|
|
|
{
|
|
typedef int Type;
|
|
std::vector<std::vector<Type>> is{{0}, {1, 2}};
|
|
for (auto& i : is[1]) std::cout << i << std::endl;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
#if __cplusplus >= 201103L
|
|
|
|
/*
|
|
# decltype
|
|
|
|
C++11 keyword
|
|
|
|
Replace decltype with type of an expression at compile time.
|
|
|
|
More powerful than `auto`.
|
|
*/
|
|
{
|
|
int i = 1;
|
|
float f = 2.0;
|
|
decltype(i + f) f2 = 1.5;
|
|
assert(f2 == 1.5);
|
|
|
|
//implies reference while auto does not
|
|
{
|
|
int i = 0;
|
|
int& ir = i;
|
|
decltype(ir) ir2 = ir;
|
|
ir2 = 1;
|
|
assert(i == 1);
|
|
}
|
|
|
|
//can be used basically anywhere
|
|
{
|
|
int i = 0;
|
|
std::vector<decltype(i)> v;
|
|
v.push_back(0);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/*
|
|
# vla
|
|
|
|
called variable length array VLS
|
|
|
|
C99 supports this
|
|
|
|
compiler implementation:
|
|
must increment/decrement stack pointer at each array
|
|
meaning, one extra multiplication and sum for every VLA declared
|
|
|
|
*/
|
|
{
|
|
{
|
|
//cin >> i;
|
|
//int is4[i];
|
|
}
|
|
|
|
{
|
|
// ERROR: may not be initialized
|
|
//cin >> i;
|
|
//int is4[i] = {1, 2};
|
|
}
|
|
}
|
|
|
|
// # enum
|
|
{
|
|
//unlike c, already does typedef
|
|
{
|
|
enum TEXTURE {GRASS, WALL, SKY};
|
|
TEXTURE t = GRASS;
|
|
}
|
|
}
|
|
|
|
// # typedef
|
|
{
|
|
// It is possible to call constructors with typedefs
|
|
{
|
|
typedef Base BaseTypedef;
|
|
BaseTypedef b = BaseTypedef(1);
|
|
// ^^^^^^^^^^^
|
|
}
|
|
|
|
// Typdefs inside classes follow public / private scoping.
|
|
{
|
|
ClassWithTypedef::typedefPublic i;
|
|
// ERROR: not accessible from this context
|
|
//ClassWithTypedef::typedefPrivate j;
|
|
}
|
|
}
|
|
|
|
// # for
|
|
{
|
|
|
|
//you can define i inside the for scope only
|
|
int is[] = {0, 1, 2};
|
|
for (int i=0; i<3; i++)
|
|
{
|
|
assert(i == is[i]);
|
|
// ERROR: already declared in this scope
|
|
//int i;
|
|
}
|
|
}
|
|
|
|
#if __cplusplus >= 201103L
|
|
|
|
#endif
|
|
|
|
// # function
|
|
{
|
|
// # overload
|
|
{
|
|
overload(1);
|
|
assert(callStack.back() == "overload(int)");
|
|
callStack.clear();
|
|
|
|
//base type conversions
|
|
{
|
|
overload(1.0f);
|
|
|
|
/*
|
|
ERROR
|
|
ambiguous overload(int) overload(float)
|
|
compiler does not know wether convert double to float or int
|
|
*/
|
|
//overload(1.0);
|
|
}
|
|
|
|
assert(callStack.back() == "overload(float)");
|
|
callStack.clear();
|
|
|
|
/*
|
|
ERROR: ambiguous
|
|
should compiler coverts to Base or BaseProtected? Both are possible via the default copy constructors.
|
|
*/
|
|
{
|
|
Class cOverload;
|
|
//overloadBase(cOverload);
|
|
}
|
|
|
|
// ERROR: ambiguous
|
|
//i=4;
|
|
//overloadValAddr(i);
|
|
|
|
// # default arguments
|
|
{
|
|
assert(DefaultArgs(1) == 1);
|
|
assert(DefaultArgs(1, 1) == 2);
|
|
}
|
|
|
|
/*
|
|
# default arguments for references
|
|
|
|
There seems to be no standard way of doing that without using extra memory / verbosity.
|
|
|
|
<http://stackoverflow.com/questions/2816293/passing-optional-parameter-by-reference-in-c>
|
|
*/
|
|
}
|
|
|
|
/*
|
|
In C++, unlike in C, definitions can ommit argument names if they don't use those arguments!
|
|
|
|
This probably exists for method overridding.
|
|
*/
|
|
{
|
|
assert(def_no_argname(0) == 1);
|
|
assert(def_no_argname(0, 0) == 2);
|
|
}
|
|
|
|
/*
|
|
# operator overload
|
|
*/
|
|
{
|
|
//OperatorOverload overload `+`
|
|
{
|
|
//==
|
|
assert(OperatorOverload(3) == OperatorOverload(3));
|
|
|
|
//<
|
|
assert(OperatorOverload(1) < OperatorOverload(2));
|
|
|
|
//=
|
|
{
|
|
OperatorOverload i(1);
|
|
assert(i == OperatorOverload(1));
|
|
}
|
|
|
|
//+=
|
|
{
|
|
OperatorOverload i(1);
|
|
i += OperatorOverload(2);
|
|
assert(i == OperatorOverload(3));
|
|
}
|
|
|
|
//+
|
|
assert(OperatorOverload(1) + OperatorOverload(2) == OperatorOverload(3));
|
|
|
|
//++
|
|
{
|
|
OperatorOverload i(1);
|
|
assert(++i == OperatorOverload(2));
|
|
assert(i == OperatorOverload(2));
|
|
|
|
/* TODO understand and get working */
|
|
/*
|
|
i = OperatorOverload(1);
|
|
assert(i++ == OperatorOverload(1));
|
|
assert(i == OperatorOverload(2));
|
|
*/
|
|
}
|
|
|
|
//-
|
|
{
|
|
// Unary
|
|
assert(-OperatorOverload(1) == OperatorOverload(-1));
|
|
|
|
// Subtraction
|
|
assert(OperatorOverload(2) - OperatorOverload(1) == OperatorOverload(1));
|
|
}
|
|
|
|
//*
|
|
{
|
|
// Dereference
|
|
assert(*(OperatorOverload(1)) == 1);
|
|
|
|
// Subtraction
|
|
assert(OperatorOverload(2) - OperatorOverload(1) == OperatorOverload(1));
|
|
}
|
|
|
|
//<<
|
|
{
|
|
OperatorOverload i(123);
|
|
std::stringstream os;
|
|
os << i;
|
|
assert(os.str() == "123");
|
|
}
|
|
|
|
//typecast overload
|
|
{
|
|
OperatorOverload oo(1);
|
|
|
|
// Explicit typecast:
|
|
assert(((bool)oo) == true);
|
|
assert(((int)oo) == 2);
|
|
assert(((float)oo) == 1.5);
|
|
|
|
// Implicit typecast:
|
|
assert(oo);
|
|
|
|
int i = oo;
|
|
assert(i == 2);
|
|
|
|
float f = oo;
|
|
assert(f == 1.5f);
|
|
}
|
|
}
|
|
|
|
/*
|
|
Explicit call syntax.
|
|
|
|
Does the same as the implicit call syntax, but is uglier.
|
|
|
|
May be required when the function is also a template function.
|
|
*/
|
|
{
|
|
OperatorOverload i, j;
|
|
i = OperatorOverload(1);
|
|
j = OperatorOverload(2);
|
|
|
|
assert(operator+(i, j) == OperatorOverload(3));
|
|
|
|
i.operator=(j);
|
|
assert(i == j);
|
|
}
|
|
|
|
/*
|
|
operator overload and templates
|
|
*/
|
|
{
|
|
// Works because of template ty.
|
|
assert(OperatorOverload(1) / OperatorOverload(2) == OperatorOverload(3));
|
|
|
|
// ERROR: Impossible syntax
|
|
//assert(OperatorOverload(1) /<OperatorOverload> OperatorOverload(2) == OperatorOverload(3));
|
|
|
|
// If we needed to specify the template parameter to the operator on this case,
|
|
// an explicit `operator/` call would be needed
|
|
assert(operator/<OperatorOverload>(OperatorOverload(1), OperatorOverload(2)) == OperatorOverload(3));
|
|
}
|
|
}
|
|
|
|
|
|
#if __cplusplus >= 201103L
|
|
|
|
/*
|
|
# lambda
|
|
|
|
C++11
|
|
|
|
Function without name.
|
|
|
|
Specialy useful in conjunction with function that take functions as arguments such as `std::find_if`,
|
|
when we only want to use the function passed once.
|
|
|
|
Good explanation: <http://stackoverflow.com/a/7627218/895245>
|
|
|
|
TODO: why square brackets? Why not pass by reference as in a regular function?
|
|
*/
|
|
{
|
|
{
|
|
int i = 0;
|
|
int j = 0;
|
|
auto f = [&i,&j](int k) -> int {i = 1; j = 1; return k + 1;};
|
|
assert(f(0) == 1);
|
|
assert(i == 1);
|
|
assert(j == 1);
|
|
}
|
|
|
|
// Typical application with find_if.
|
|
{
|
|
std::vector<int> v = {2, 0, 1};
|
|
assert(std::find_if(v.begin(), v.end(),
|
|
[](int i) {return i % 2 == 1;}) == --v.end());
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
/*
|
|
# template
|
|
|
|
Greatly reduces code duplication
|
|
|
|
Can be used both in functions and classes.
|
|
|
|
For each template that is used, a new name mangled function is compiled.
|
|
This has the following downsides:
|
|
|
|
- code bloat.
|
|
|
|
Final exectutable gets larger.
|
|
|
|
- Implementation must be put in `.h` files and compiled by includers,
|
|
since only used templates generate code for the corresponding definitions.
|
|
|
|
Pre-compiling all possibilities on a `.so` is obviously not an option:
|
|
just consider int N, there are int many compilation possibilities!
|
|
|
|
# three types of arguments
|
|
|
|
There are 3 possible arguments for templates:
|
|
|
|
- types
|
|
- integers values
|
|
- other templates (see template teamplate)
|
|
|
|
# extends
|
|
|
|
No equivalent to Javas "T extends Drawable"... sad.
|
|
|
|
But wait, there seems to be something coming on C++14: template restrictions to the rescue?
|
|
<http://stackoverflow.com/questions/15669592/what-are-the-differences-between-concepts-and-template-constraints>
|
|
|
|
# disambiguating dependent qualified type names
|
|
|
|
Syntax:
|
|
|
|
template <class T>
|
|
std::string foo(vector<T> vec, ... other args)
|
|
{
|
|
typename std::vector<T>::iterator it = vec.begin();
|
|
}
|
|
|
|
source:
|
|
|
|
<http://eli.thegreenplace.net/2011/04/22/c-template-syntax-patterns/>
|
|
|
|
TODO0
|
|
|
|
# Disambiguating explicitly qualified template member usage
|
|
|
|
Syntax:
|
|
|
|
template<class U> void func(U arg)
|
|
{
|
|
int obj = arg.template member_func<int>();
|
|
}
|
|
|
|
Source: http://eli.thegreenplace.net/2011/04/22/c-template-syntax-patterns/
|
|
|
|
TODO0
|
|
|
|
# sources
|
|
|
|
- <http://www.codeproject.com/Articles/257589/An-Idiots-Guide-to-Cplusplus-Templates-Part-1>
|
|
|
|
Very complete and exemplified intro article.
|
|
|
|
- <http://eli.thegreenplace.net/2011/04/22/c-template-syntax-patterns/>
|
|
|
|
Short intro, covers some quirky points.
|
|
*/
|
|
{
|
|
|
|
/*
|
|
basic usage
|
|
*/
|
|
{
|
|
assert(templateAdd<int>(1, 1) == 2);
|
|
assert(templateAdd<float>(1.0, 1.0) == 2);
|
|
}
|
|
|
|
/*
|
|
# template specialization
|
|
|
|
Give an specific behaviour for certain types.
|
|
*/
|
|
{
|
|
assert((templateSpec<double,double>(1.0, 1.0)) == 3.1);
|
|
}
|
|
|
|
/*
|
|
# template argument deduction
|
|
|
|
Deduce the template parameters based on the type of the arguments passed to the function,
|
|
when those arguments are typenames used in the template.
|
|
|
|
Only works for function templates, not for class templates.
|
|
Why not do it for class templates via constructor:
|
|
<http://stackoverflow.com/questions/984394/why-not-infer-template-parameter-from-constructor?rq=1>
|
|
|
|
Complex rules dictate how this happens: <http://accu.org/index.php/journals/409>
|
|
|
|
The advantages are:
|
|
|
|
- write less
|
|
- don't repeat yourself: if
|
|
|
|
However it does make the code harder to understand,
|
|
since readers have to deduce types in their heads to decide which functions will be called.
|
|
|
|
In the casse of operators, templates enourmously help with syntatic sugar as:
|
|
|
|
cout << "a";
|
|
|
|
would have to be written something like:
|
|
|
|
operator<<<ostream,string>(cout, "a");
|
|
|
|
if there was no template argument deduction, and that would be ugly.
|
|
*/
|
|
{
|
|
/*
|
|
The compiler calls the int or double version depending on the function argument!
|
|
|
|
If no template parameters need to be passed, the template notation can be ommited completely.
|
|
|
|
TODO check
|
|
*/
|
|
{
|
|
assert(templateArgDeduct<int> (1) == 1);
|
|
assert(templateArgDeduct (1) == 1);
|
|
assert(templateArgDeduct<double>(1.0) == 2.0);
|
|
assert(templateArgDeduct (1.0) == 2.0);
|
|
}
|
|
|
|
/*
|
|
Can only deduct parameters which are function arguments,
|
|
not those used only on return types or other places.
|
|
*/
|
|
{
|
|
assert((templateArgDeductReturn<int>()) == 0);
|
|
assert((templateArgDeductLocal<int>()) == 0);
|
|
|
|
// ERROR.
|
|
//assert((templateArgDeductReturn<>()) == 0);
|
|
//assert((templateArgDeductLocal<>()) == 0);
|
|
}
|
|
|
|
/*
|
|
Can only deduct parmeters if the parameter is the last non deducted one.
|
|
|
|
Here `U` cannot be deducted because it is not a function parameter,
|
|
so `T` which could be deducted cannot because it is never the last undeduced one.
|
|
*/
|
|
{
|
|
assert((templateArgDeductNotLast<int,int>(1)) == 1);
|
|
|
|
// ERROR.
|
|
//assert((templateArgDeductNotLast<int>(1)) == 1);
|
|
}
|
|
|
|
/*
|
|
argument deduction works!! even if the `int` is not a direct function argument,
|
|
but a template argument to a function argument `TemplateTemplateParam<int>`.
|
|
*/
|
|
{
|
|
assert(templateArgTemplateArg (TemplateTemplateParam<int>(1)) == 1);
|
|
assert(templateArgTemplateArg<int>(TemplateTemplateParam<int>(1)) == 1);
|
|
}
|
|
|
|
/*
|
|
# typename keyword qualifier
|
|
|
|
Besides the basic usage of typename for defining templates,
|
|
it must also be used under certain conditions to allow the compiler to parse the program
|
|
when templates are used.
|
|
|
|
Simple intro to typename: <http://pages.cs.wisc.edu/~driscoll/typename.html>
|
|
|
|
Explains well the denominations in the standard: <http://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-the-template-and-typename-keywords>
|
|
|
|
Can only be used inside of template classes or functions.
|
|
|
|
Typename rule: qualified dependent names are always parsed
|
|
as values and not types umless they have the typename keyword.
|
|
|
|
If they are put on a place which only accepts types and not values,
|
|
this must generate a compile time error!
|
|
*/
|
|
{
|
|
// WARNING: statement `HasIMember::i` has no effect
|
|
|
|
//NoTypenameFunc<HasIMember>();
|
|
|
|
// ERROR: dependant name is parsed as non type
|
|
|
|
//NoTypenameFunc<HasIType>();
|
|
|
|
// ERROR: no type named i in HasIMember
|
|
|
|
//TypenameFunc<HasIMember>();
|
|
|
|
TypenameFunc<HasIType>();
|
|
|
|
// ERROR.
|
|
|
|
//NoTypenameInTemplateFunc<HasIType>();
|
|
|
|
//ERROR.
|
|
|
|
//NoTypenameInTemplateFunc<HasIMember>();
|
|
|
|
// ERROR.
|
|
|
|
TypenameInTemplateFunc<HasIType>();
|
|
|
|
// ERROR.
|
|
|
|
//TypenameInTemplateFunc<HasIMember>();
|
|
}
|
|
|
|
/*
|
|
# template keyword qualifier
|
|
|
|
Just like the typename qualifier helps the compiler solve another type of parsing ambiguity,
|
|
in this case if `<` is a minus or a template instantiation.
|
|
|
|
Only used inside of templates that use templates!
|
|
|
|
Very good example of the template qualifier:
|
|
<http://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-the-template-and-typename-keywords>
|
|
*/
|
|
{
|
|
TemplateQualifier tq;
|
|
TemplateQualifierTest<TemplateQualifier>(tq, tq, &tq);
|
|
}
|
|
}
|
|
|
|
/*
|
|
# Template integer parameter
|
|
|
|
Templates can receive integer parameters
|
|
|
|
Those parameters must be constexpr.
|
|
*/
|
|
{
|
|
assert(templateAddInt<1>(1) == 2);
|
|
}
|
|
|
|
// Not a constexpr.
|
|
{
|
|
//std::cout << templateAddInt<std::time(NULL) >(1) << std::endl;
|
|
}
|
|
|
|
/*
|
|
# Template recursion
|
|
|
|
May lead to huge code bloat, but also great speads and non repetition.
|
|
*/
|
|
{
|
|
assert(factorial<3>() == 6);
|
|
//because of this call
|
|
//all factorials from
|
|
//1 to 3 will be compiled
|
|
|
|
assert(factorial<6>() == 720);
|
|
//because of this call
|
|
//all factorials from
|
|
//4 to 6 will be compiled
|
|
}
|
|
|
|
/*
|
|
# template template parameters
|
|
|
|
Passing a template as a template argument.
|
|
*/
|
|
{
|
|
/*
|
|
This does not compile: template template arguments are required.
|
|
*/
|
|
{
|
|
//TemplateTemplateIntNotATemplate<int,TemplateTemplateParam>
|
|
}
|
|
|
|
//useless working example
|
|
{
|
|
TemplateTemplateInt<TemplateTemplateParam> t;
|
|
t.t.t = 1;
|
|
}
|
|
|
|
/*
|
|
This is an example illustrates a case in which a template teamplate would be useful:
|
|
|
|
- to enforce that a single template argument will be used on many places
|
|
- to allow users to write a type only once
|
|
*/
|
|
{
|
|
/* bad: types don't match */
|
|
TemplateTemplateWouldBeBetter<int,TemplateTemplateParam<double>> t;
|
|
|
|
/* bad: types match, but there is code duplication as `int` must be written twice */
|
|
TemplateTemplateWouldBeBetter<int,TemplateTemplateParam<int>> t2;
|
|
}
|
|
|
|
/*
|
|
This solves the above issues
|
|
*/
|
|
{
|
|
TemplateTemplate<int,TemplateTemplateParam> t;
|
|
t.v.t = 0;
|
|
t.t = 0;
|
|
|
|
/**/
|
|
assert(t.equal());
|
|
}
|
|
}
|
|
|
|
//double less signs: can only be used in C++11.
|
|
//or compiler could get confused with `>>` operator
|
|
{
|
|
{std::vector<std::vector<int> > vv;}
|
|
// ^
|
|
// THIS space was required before C++11
|
|
|
|
#if __cplusplus >= 201103L
|
|
{std::vector<std::vector<int>> vv;}
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
# template multiple parameters
|
|
|
|
Templates can have multiple parameters of any kind of type.
|
|
*/
|
|
{
|
|
/*
|
|
# Comma protection gotcha
|
|
|
|
The C++ preprocessor does not protect commas inside `<`, so the protecting parenthesis (1)
|
|
and (2) are necessary.
|
|
*/
|
|
{
|
|
assert((templateDefault<int,TemplateTemplateParam,1>(1, TemplateTemplateParam<int>(1))) == 3);
|
|
// ^ ^
|
|
// 1 2
|
|
|
|
// ERROR: assert macro gets too many arguments, because `<>` does not protect its inner commas.
|
|
//assert(templateDefault<int,TemplateTemplateParam,1>(1, TemplateTemplateParam<int>(1)) == 3);
|
|
// ^ ^
|
|
// 1 2
|
|
}
|
|
|
|
// Reuse a type.
|
|
{
|
|
assert((TemplateReuseType<int,1>()) == 1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
# template default parameters
|
|
|
|
Each of the 3 parameters types that can be passed to templates can have defaults.
|
|
*/
|
|
{
|
|
assert((templateDefault<int,TemplateTemplateParam,1>(1, TemplateTemplateParam<int>(1))) == 3);
|
|
assert((templateDefault<int,TemplateTemplateParam >(1, TemplateTemplateParam<int>(1))) == 3);
|
|
assert((templateDefault<int >(1, TemplateTemplateParam<int>(1))) == 3);
|
|
assert((templateDefault< >(1, TemplateTemplateParam<int>(1))) == 3);
|
|
//if there are no parameters left, the `<>` can be ommited:
|
|
assert((templateDefault (1, TemplateTemplateParam<int>(1))) == 3);
|
|
}
|
|
|
|
#if __cplusplus >= 201103L
|
|
/*
|
|
# variadic template
|
|
*/
|
|
{
|
|
assert(variadicSum(1) == 1);
|
|
assert(variadicSum(1, 2) == 3);
|
|
assert(variadicSum(1, 2, 3) == 6);
|
|
|
|
assert(fabs(variadicSum(0.1) - 0.1) < 1e-6);
|
|
assert(fabs(variadicSum(0.1, 0.2) - 0.3) < 1e-6);
|
|
assert(fabs(variadicSum(0.1, 0.2, 0.3) - 0.6) < 1e-6);
|
|
|
|
assert(variadicSum(1, 1.0) == 2.0);
|
|
|
|
/*
|
|
# sizeof...
|
|
|
|
Return number of template arguments passed to tempalte.
|
|
*/
|
|
{
|
|
assert( VariadicSizeof<>() == 0 );
|
|
assert( VariadicSizeof<int>() == 1 );
|
|
assert((VariadicSizeof<int,int>() == 2));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
# SFINAE
|
|
|
|
<http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error>
|
|
|
|
TODO0
|
|
*/
|
|
|
|
/*
|
|
# template class
|
|
|
|
Only points which differ significantly from template functions shall be covered here.
|
|
*/
|
|
{
|
|
{
|
|
TemplateClass<Base,int,10> c;
|
|
c.ts[9] = 9;
|
|
}
|
|
|
|
{
|
|
TemplateClass<Base,std::string,10> c;
|
|
c.ts[9] = "asdf";
|
|
}
|
|
|
|
{
|
|
TemplateClass<> c; //default values int 10
|
|
|
|
// ERROR: canot ommit `<>` for template classes
|
|
//TemplateClass c2;
|
|
}
|
|
|
|
// BAD: wont work, unless you defined an assign operator for this case
|
|
// which is very unlikelly
|
|
//tci10 = TemplateClass<float,20>();
|
|
|
|
{
|
|
Class c;
|
|
c.methodTemplate<int>();
|
|
}
|
|
|
|
{
|
|
TemplateClass<>().methodTemplate<>();
|
|
}
|
|
|
|
{
|
|
{
|
|
TemplateClass<Base,int,10> c;
|
|
callStack.clear();
|
|
c.methodDefinedOutside();
|
|
assert(callStack.back() == "TemplateClass::methodDefinedOutside()");
|
|
// 12 class does not contain method().
|
|
//TemplateClass<Base,int,12>().method();
|
|
}
|
|
|
|
{
|
|
TemplateClass<Base,int,11> c;
|
|
callStack.clear();
|
|
c.methodDefinedOutside();
|
|
assert(callStack.back() == "TemplateClass<Base,int,11>::methodDefinedOutside()");
|
|
//TemplateClass<Base,int,12>().method();
|
|
//12 class does not contain method()
|
|
}
|
|
|
|
{
|
|
TemplateClass<Base,int,12> c;
|
|
callStack.clear();
|
|
c.newMethod();
|
|
assert(callStack.back() == "TemplateClass<Base,int,12>::newMethod()");
|
|
//TemplateClass<Base,int,12>().method();
|
|
//12 class does not contain method()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
# exception #throw #catch
|
|
|
|
Great source: <http://www.cplusplus.com/doc/tutorial/exceptions/>
|
|
|
|
Application: centralize error handling in a single place, even if outside executing functions.
|
|
|
|
The application is similar to C's longjmp, but the implementation is different.
|
|
TODO how are they implemented in assembly code? <http://stackoverflow.com/questions/490773/how-is-the-c-exception-handling-runtime-implemented>
|
|
It is more magic than C longjmp as it does type checking.
|
|
|
|
Anything can be thrown, but the most standard and extensible method is to throw subclasses of exception,
|
|
so just do that always.
|
|
|
|
There is no finally block: <http://stackoverflow.com/questions/161177/does-c-support-finally-blocks-and-whats-this-raii-i-keep-hearing-about>
|
|
Deinitializations are left for destructors.
|
|
|
|
# Standard exceptions.
|
|
|
|
- exception base class of all stdlib exceptions.
|
|
- bad_alloc thrown by new on allocation failure
|
|
- bad_cast thrown by dynamic_cast when fails with a referenced type
|
|
- bad_exception thrown when an exception type doesn't match any catch
|
|
- bad_typeid thrown by typeid
|
|
- ios_base::failure thrown by functions in the iostream library
|
|
|
|
# exception safety
|
|
|
|
Different levels of how much excpetion handlind a function does:
|
|
|
|
<http://en.wikipedia.org/wiki/Exception_safety>
|
|
*/
|
|
{
|
|
/*
|
|
Exceptions can jump out of functions.
|
|
|
|
This is their main reason for existing!
|
|
*/
|
|
{
|
|
try {
|
|
exception_func_int();
|
|
} catch (int i) {
|
|
assert(i == 1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
# std::exception
|
|
|
|
Anything can be thrown, including classes and base types.
|
|
|
|
All stdlib exceptions inherit from `exception`, so it is a good idea to only throw
|
|
things inherited from it.
|
|
|
|
`std::exception` has limited use since its constructor does not take any arguments,
|
|
so you cannot describe the error. Some stdlib derived class constructors do however.
|
|
*/
|
|
{
|
|
try {
|
|
throw std::exception();
|
|
} catch (std::exception e) {
|
|
}
|
|
}
|
|
|
|
/*
|
|
Catch blocks work like function overloads and catch by type.
|
|
*/
|
|
try {
|
|
throw 'c';
|
|
} catch (int i) {
|
|
assert(false);
|
|
} catch (char c) {
|
|
}
|
|
|
|
/*
|
|
`...` is the default case
|
|
*/
|
|
try {
|
|
throw 1.0;
|
|
} catch (int i) {
|
|
assert(false);
|
|
} catch (char c) {
|
|
assert(false);
|
|
} catch (...) {
|
|
}
|
|
|
|
/*
|
|
Derived classes.
|
|
|
|
Just like for function overloading, base classes catch for derived classes.
|
|
*/
|
|
{
|
|
try {
|
|
throw myexception();
|
|
} catch (std::exception& ex) {
|
|
}
|
|
/*
|
|
This compiles, but generates a warning, since the first catch will always catch instead of this one.
|
|
*/
|
|
//catch (myexception& ex) {assert(false);}
|
|
catch (...) {assert(false);}
|
|
|
|
/*
|
|
this is a more common exception ordering, first derived then base.
|
|
*/
|
|
{
|
|
try {
|
|
throw myexception();
|
|
} catch (myexception& ex) {
|
|
} catch (std::exception& ex) {
|
|
assert(false);
|
|
} catch (...) {
|
|
assert(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
# what
|
|
|
|
Returns a string which contains information about the exception.
|
|
|
|
Many stdlib exceptions simply return the error message given on the constructor.
|
|
*/
|
|
{
|
|
std::string msg = "custom message";
|
|
std::ios_base::failure e(msg);
|
|
// TODO worked in GCC 4.8, failed in GCC 5.1.
|
|
//assert(e.what() == msg);
|
|
}
|
|
|
|
/*
|
|
# uncaught exceptions
|
|
|
|
Uncaught exceptions explose at top level and terminate the program.
|
|
|
|
Check out the error messages generated by each exception.
|
|
|
|
Classes that derive from exception and implement `what()` can print custom messages,
|
|
which may contain useful debug info. This is a major point in favor of using exception
|
|
classes instead of base types.
|
|
*/
|
|
{
|
|
//throw 1;
|
|
//throw 'c';
|
|
//throw 1.0;
|
|
//throw myexception();
|
|
}
|
|
|
|
/*
|
|
# exception specifications
|
|
|
|
Functions can specify which exceptions are catchable with the following syntax.
|
|
*/
|
|
{
|
|
try {
|
|
exception_func_int_only(true);
|
|
} catch (int i) {
|
|
} catch (...) {
|
|
assert(false);
|
|
}
|
|
|
|
try {
|
|
//exception_func_int_only(false);
|
|
} catch (...) {
|
|
/* not even ... this can catch non int exceptions thrown by this function */
|
|
}
|
|
|
|
try {
|
|
exception_func_int_exception_only(1);
|
|
} catch (int i) {
|
|
} catch (myexception& ex) {
|
|
} catch (...) {
|
|
assert(false);
|
|
}
|
|
|
|
try {
|
|
//exception_func_none();
|
|
} catch (...) {
|
|
/* no exception thrown by this function is catchable */
|
|
}
|
|
|
|
try {
|
|
//exception_func_none_wrapper();
|
|
} catch (...) {
|
|
/* the same goes if we wrap the function */
|
|
}
|
|
}
|
|
|
|
/*
|
|
# exception from destructor
|
|
|
|
Never throw an exception from a destructor.
|
|
|
|
Destructors are meant to clean up after exceptions, so if you throw exceptions from them,
|
|
things get messy.
|
|
|
|
C++ specifies that if this happens during stack unwinding, the program may terminate!
|
|
|
|
What to do to avoid that: <http://stackoverflow.com/questions/130117/throwing-exceptions-out-of-a-destructor>
|
|
|
|
The following code could lead to that.
|
|
*/
|
|
if (0) {
|
|
try {
|
|
ExceptionDestructor e;
|
|
} catch (...) {
|
|
}
|
|
|
|
try {
|
|
ExceptionDestructorCaller();
|
|
} catch (...) {
|
|
}
|
|
}
|
|
|
|
#if __cplusplus >= 201103L
|
|
/*
|
|
# noexcept
|
|
|
|
Improved version of `throw` for functions.
|
|
|
|
`throw` for functions becomes deprecated in C++11.
|
|
|
|
TODO
|
|
*/
|
|
{
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// # class
|
|
{
|
|
#if __cplusplus >= 201103L
|
|
/*
|
|
define class inside function
|
|
*/
|
|
{
|
|
// As of C++11, classes can be defined inside functions!
|
|
// This matches the behaviour for structs in C.
|
|
{
|
|
class C {};
|
|
}
|
|
|
|
// Template classes however cannot be defined in functions.
|
|
// Just think what should the compiler do in this case?
|
|
{
|
|
//template<class T> class C {};
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
# Constructor
|
|
|
|
Called whenever object is created to initialize the object.
|
|
*/
|
|
{
|
|
/*
|
|
# Default constructors
|
|
|
|
<http://en.cppreference.com/w/cpp/language/default_constructor>
|
|
|
|
Constructor that takes no arguments.
|
|
|
|
Can be one explicitly created by the programmer:
|
|
all that matters is that it takes no arguments.
|
|
|
|
It is a good idea to always implement a default constructor,
|
|
since this is the only way arrays of fixed numbers of objects can be created before C++03
|
|
|
|
The concept of default constructor exists because there are
|
|
certain differences in syntax and behaviour when using default constructors,
|
|
for example:
|
|
|
|
- the most vexing parse only happens for default constructors.
|
|
- the default constructor can be is implicitly declared and defiend by the compiler.
|
|
|
|
# Implicily declared constructors
|
|
|
|
If no explicit constructor is declared,
|
|
the compiler automatically declares the following functions:
|
|
|
|
- default constructor
|
|
- copy constructor
|
|
- assignment constructor
|
|
- destructor
|
|
|
|
If any constructor is explicitly declared, even one taking multiple default args,
|
|
then *none* of the implicitly declared constructors are declared: that must be done manually.
|
|
|
|
# Trivial default constructor
|
|
|
|
# Implicily defined default constructor
|
|
|
|
If the implicitly-declared default constructor is not deleted
|
|
or trivial, it is defined (that is, a function body is generated
|
|
and compiled) by the compiler, and it has exactly the same effect
|
|
as a user-defined constructor with empty body and empty initializer list.
|
|
That is, it calls the default constructors of the bases
|
|
and of the non-static members of this class.
|
|
|
|
In particular, the IDDC does not do zero initialization on non-class members
|
|
such as `int`, so those have undefined values.
|
|
*/
|
|
{
|
|
// To call the default constructor, use this syntax
|
|
{
|
|
callStack.clear();
|
|
NoBaseNoMember c; //default constructor was called!
|
|
std::vector<std::string> expectedCallStack = {
|
|
"NoBaseNoMember::NoBaseNoMember()",
|
|
};
|
|
assert(callStack == expectedCallStack);
|
|
}
|
|
|
|
/*
|
|
The implicitly defined default constructor does not necessarily initialize member built-in types:
|
|
http://stackoverflow.com/questions/2417065/does-the-default-constructor-initialize-built-in-types
|
|
|
|
Class member default constructors however are called.
|
|
*/
|
|
{
|
|
ImplicitDefaultCtor o;
|
|
if (o.i != 0)
|
|
// undefined behaviour.
|
|
std::cout << "ImplicitDefaultCtor undefined behaviour: o.i = " << o.i << std::endl;
|
|
|
|
// Defined behaviour because class:
|
|
assert(o.s == "");
|
|
|
|
// *however*, the following does value initialization,
|
|
// not the default constructor, and built-in members are indeed 0 initialized!
|
|
{
|
|
ImplicitDefaultCtor o = ImplicitDefaultCtor();
|
|
assert(o.i == 0);
|
|
}
|
|
}
|
|
|
|
{
|
|
// ERROR:
|
|
//NoDefaultCtor o;
|
|
|
|
// ERROR cannot be done because this class has not default constructors.
|
|
//NoDefaultCtor os[2];
|
|
|
|
// Implicit copy and assign are still defined:
|
|
NoDefaultCtor o(1);
|
|
NoDefaultCtor o2(o);
|
|
o = o2;
|
|
}
|
|
|
|
#if __cplusplus >= 201103L
|
|
/*
|
|
# Default keyword
|
|
|
|
As of C++11, the `= default` statement can be added to a constructor to explicitly
|
|
say that the default should be used.
|
|
|
|
This allows a class to have multple constructors,
|
|
plus the implictly defined one.
|
|
*/
|
|
{
|
|
DefaultKeyword o;
|
|
//assert(o.i == 0); // undefined behaviour
|
|
assert(o.s == std::string());
|
|
|
|
o = DefaultKeyword(1, "a");
|
|
assert(o.i == 1);
|
|
assert(o.s == "a");
|
|
}
|
|
|
|
/*
|
|
# Delete keyword
|
|
*/
|
|
{
|
|
// ERROR: Explicitly deleted:
|
|
//DeleteKeyword o;
|
|
|
|
DeleteKeyword o(1);
|
|
|
|
// ERROR: Explicitly deleted:
|
|
//DeleteKeyword o2(o);
|
|
|
|
DeleteKeyword o2(2);
|
|
|
|
// ERROR: Explicitly deleted:
|
|
//o2 = o1;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
# Most vexing parse
|
|
|
|
Default constructor vs function declaration syntax gotcha!
|
|
|
|
<http://stackoverflow.com/questions/180172/default-constructor-with-empty-brackets>
|
|
*/
|
|
{
|
|
/*
|
|
BAD
|
|
|
|
Declares *FUNCTION* called `c` that returns `Class` inside function main.
|
|
|
|
This is the same as in C, where it is possible to declare a function from inside another function,
|
|
but not define it.
|
|
|
|
Therefore there would be not way for C++ to distinguish between the two,
|
|
and still be backwards compatible with C.
|
|
*/
|
|
{
|
|
Class c();
|
|
|
|
// ERROR: function definition is not possible inside another function.
|
|
|
|
//Class c() {return Class();}
|
|
|
|
//c.i;
|
|
}
|
|
|
|
// If you want to call a default constructor, use:
|
|
{
|
|
Class c;
|
|
assert(c.i == 0);
|
|
}
|
|
|
|
/*
|
|
For non-default constructors, things work as expected,
|
|
as this syntax could not possibly be a function declaration.
|
|
*/
|
|
{
|
|
Class c(1);
|
|
assert(c.i == 1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
Value initialization and zero initialization are both a bit subtle, so it is best not to rely on them.
|
|
|
|
# value initialization
|
|
|
|
<http://en.cppreference.com/w/cpp/language/value_initialization>
|
|
|
|
# aggregate initialization
|
|
|
|
<http://en.cppreference.com/w/cpp/language/aggregate_initialization>
|
|
|
|
# POD
|
|
|
|
Plain old data:
|
|
|
|
<http://stackoverflow.com/questions/4178175/what-are-aggregates-and-pods-and-how-why-are-they-special>
|
|
|
|
# zero initialization
|
|
|
|
<http://en.cppreference.com/w/cpp/language/zero_initialization>
|
|
|
|
<http://stackoverflow.com/questions/1613341/what-do-the-following-phrases-mean-in-c-zero-default-and-value-initializat>
|
|
*/
|
|
{
|
|
// Syntax with new.
|
|
{
|
|
// Base types.
|
|
{
|
|
int* is = new int[2]();
|
|
assert(is[0] == 0);
|
|
assert(is[1] == 0);
|
|
delete[] is;
|
|
}
|
|
|
|
// Works for structs.
|
|
{
|
|
struct T {int a;};
|
|
T *t = new T[1]();
|
|
assert(t[0].a == 0);
|
|
delete[] t;
|
|
}
|
|
|
|
/*
|
|
Works for objects.
|
|
|
|
Note how the default constructor was called since `z == 1`.
|
|
*/
|
|
{
|
|
{
|
|
Class *cs = new Class[1]();
|
|
assert(cs[0].i == 0);
|
|
assert(cs[0].z == 1);
|
|
delete[] cs;
|
|
}
|
|
}
|
|
|
|
// But only works with default constructors.
|
|
{
|
|
//Class *cs = new [1](1);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
# initialize built-in types
|
|
|
|
<http://stackoverflow.com/questions/5113365/do-built-in-types-have-default-constructors>
|
|
|
|
C++ adds new ways to initialize base types.
|
|
|
|
Those are not however constructors.
|
|
|
|
They probably just mimic constructor syntax to help blurr the distinction
|
|
between built-in types and classes.
|
|
*/
|
|
{
|
|
// Parenthesis initialization
|
|
{
|
|
int i(1);
|
|
assert(i == 1);
|
|
}
|
|
|
|
{
|
|
// Most vexing parse.
|
|
//int i();
|
|
}
|
|
|
|
{
|
|
int i = int();
|
|
assert(i == 0);
|
|
}
|
|
|
|
#if __cplusplus >= 201103L
|
|
/*
|
|
# Brace initialization of scalars
|
|
|
|
See uniform initialization.
|
|
|
|
<http://stackoverflow.com/questions/14232184/initializing-scalars-with-braces>
|
|
|
|
# Uniform initialization
|
|
|
|
In c++11 every type can be initialized consistently with `{}`.
|
|
|
|
Advantages:
|
|
|
|
- non verbose initialization of multiple structures
|
|
- reduces syntax barriers between objects and built-in classes.
|
|
|
|
Disadvantages:
|
|
|
|
- ambiguous with initializer list construction!
|
|
- implementing the initializer list constructor breaks client code?!
|
|
because it has priority over other constructors.
|
|
*/
|
|
{
|
|
// Built-int types
|
|
{
|
|
int i{1};
|
|
assert(i == 1);
|
|
|
|
// ERROR: narrowing conversion from double to int not allowed inside `{}`
|
|
// this is the main difference between `{}` and `()` and `=`.
|
|
|
|
//int iNarrow{1.5};
|
|
|
|
// Widening types is OK:
|
|
|
|
float f{1};
|
|
|
|
// Works for arrays.
|
|
|
|
int is[]{0, 1, 2};
|
|
assert(is[1] == 1);
|
|
}
|
|
|
|
// Objects.
|
|
{
|
|
// The 2 argument constructor is called.
|
|
{
|
|
{
|
|
UniformInitializationCtor2 o{1, 1};
|
|
assert(o.i == 1);
|
|
assert(o.j == 2);
|
|
}
|
|
|
|
// Conversion gets done for passing args to functions
|
|
{
|
|
UniformInitializationCtor2 o = {1, 1};
|
|
assert(o.i == 1);
|
|
assert(o.j == 2);
|
|
|
|
assert(UniformInitializationCtor2Func({1, 1}) == 3);
|
|
|
|
assert((o == UniformInitializationCtor2{1,1}));
|
|
assert((o.operator==({1,1})));
|
|
// ERROR: TODO why does this fail to compile?
|
|
//assert((o == {1,1}));
|
|
}
|
|
}
|
|
|
|
/*
|
|
If there is an initializer list ctor, the init list wins.
|
|
|
|
This is one inconvenient of using uniform initialization.
|
|
|
|
If ever an initializer list is created, it may breaks client code
|
|
that uses the other constructor.
|
|
*/
|
|
{
|
|
UniformInitializationList o{1, 1};
|
|
assert(o.i == 1);
|
|
assert(o.j == 1);
|
|
}
|
|
|
|
// Application: initialize complex objects.
|
|
{
|
|
// With uniform init.
|
|
{
|
|
std::vector<std::pair<int,std::string> > v{
|
|
{0, "zero"},
|
|
{1, "one"},
|
|
{2, "two"},
|
|
};
|
|
|
|
assert(v[0].second == "zero");
|
|
}
|
|
|
|
// Without uniform init. Slightly less readable don't you think?
|
|
{
|
|
std::vector<std::pair<int,std::string> > v{
|
|
std::pair<int,std::string>(0, "zero"),
|
|
std::pair<int,std::string>(1, "one"),
|
|
std::pair<int,std::string>(2, "two"),
|
|
};
|
|
}
|
|
}
|
|
|
|
// TODO0 why are they different?
|
|
{
|
|
// Does this work because it is treated like a struct since it does not have constructors?
|
|
{
|
|
UniformInitializationImplicitCtor o{1, 2};
|
|
assert(o.i == 1);
|
|
assert(o.j == 2);
|
|
}
|
|
|
|
// ERROR.
|
|
{
|
|
//UniformInitializationExplicitCtor o = {1, 2};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if __cplusplus >= 201103L
|
|
// Call one constructor from constructor.
|
|
{
|
|
CtorFromCtor c(0,1);
|
|
assert((c.v == std::vector<int>{0, 1}));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if __cplusplus >= 201103L
|
|
|
|
/*
|
|
# brace enclosed initializer list
|
|
|
|
See inializer list
|
|
|
|
# list initialization
|
|
|
|
See initializer list constructor.
|
|
|
|
# initializer list contructor
|
|
|
|
Useful in cases where you don't know beforehand how many arguments
|
|
a constructor should receive.
|
|
|
|
For example, the stdlib std::vector class gets an initializer list constructor on C++11,
|
|
which allows one to initialize it to any constant.
|
|
|
|
TODO0 could this not be achieved via cstdarg?
|
|
*/
|
|
{
|
|
//STL std::vector usage example
|
|
{
|
|
std::vector<int> v{0, 1};
|
|
//std::vector<int> v = std::vector<int>({0, 1});
|
|
//SAME
|
|
assert(v[0] == 0);
|
|
assert(v[1] == 1);
|
|
assert(v == std::vector<int>({0, 1}));
|
|
assert((v == std::vector<int>{0, 1}));
|
|
|
|
// Assignment also works via implicit conversion.
|
|
v = {1, 0};
|
|
assert((v == std::vector<int>{1, 0}));
|
|
|
|
// ERROR: TODO why no implicit conversion is made?
|
|
//assert((v == {0, 1}));
|
|
}
|
|
|
|
// How to implemente one.
|
|
{
|
|
{
|
|
InitializerListCtor o{0, 1};
|
|
assert((o.v == std::vector<int>{0, 1}));
|
|
}
|
|
|
|
// Initializer list constructor is called
|
|
{
|
|
InitializerListCtor o{0, 0, 0, 0};
|
|
assert((o.v == std::vector<int>{0, 0, 0, 0}));
|
|
}
|
|
|
|
// 3 param constructor is called
|
|
{
|
|
InitializerListCtor o(0, {0, 0,}, 0);
|
|
assert((o.v == std::vector<int>{1, 0, 0, -1}));
|
|
}
|
|
}
|
|
|
|
/*
|
|
# auto and initializer lists
|
|
|
|
auto rule: brace initializer can be bound to auto
|
|
|
|
http://en.cppreference.com/w/cpp/utility/initializer_list
|
|
*/
|
|
{
|
|
{
|
|
// TODO GCC 5.1 does not allow this, which conflicts with
|
|
// http://en.cppreference.com/w/cpp/utility/initializer_list
|
|
// Who is right?
|
|
//auto l{0, 1, 2};
|
|
// SAME:
|
|
//initializer_list<int> l{0, 1, 2};
|
|
//assert(l.size() == 3);
|
|
//assert(*l.begin() == 0);
|
|
}
|
|
|
|
// The rule for auto makes this ranged for work.
|
|
// TODO0 why here? I see an `int`, not an `auto`
|
|
int i = 0;
|
|
for (int x : {0, 1, 2}) {
|
|
assert(x == i);
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
# destructor
|
|
|
|
Called when:
|
|
|
|
1) statically allocated object goes out of scope
|
|
2) dynamically allocated object gets deleted
|
|
|
|
Major application:
|
|
|
|
- delocate dynamic memory that was allocated on constructor
|
|
|
|
Virtual: not necessary *but* almost always what you want a polymorphic class
|
|
to which there will be pointers to base classes.
|
|
*/
|
|
{
|
|
callStack.clear();
|
|
|
|
{
|
|
NoBaseNoMember b;
|
|
} //destructor is called now!
|
|
|
|
std::vector<std::string> expectedCallStack = {
|
|
"NoBaseNoMember::NoBaseNoMember()",
|
|
"NoBaseNoMember::~NoBaseNoMember()"
|
|
};
|
|
assert(callStack == expectedCallStack);
|
|
}
|
|
|
|
// # array of objects
|
|
{
|
|
// Default constructor is called when array is created.
|
|
{
|
|
callStack.clear();
|
|
NoBaseNoMember os[2]; //default constructor called
|
|
std::vector<std::string> expectedCallStack = {
|
|
"NoBaseNoMember::NoBaseNoMember()",
|
|
"NoBaseNoMember::NoBaseNoMember()",
|
|
};
|
|
assert(callStack == expectedCallStack);
|
|
}
|
|
|
|
/*
|
|
To initialize the objects with a non default constructor
|
|
one possibility is to use simply use assignment for each item.
|
|
|
|
The downside of this method is that constructors are called twice
|
|
for each array element.
|
|
*/
|
|
{
|
|
callStack.clear();
|
|
|
|
NoBaseNoMember os[2]; //default constructor called
|
|
os[0] = NoBaseNoMember(0);
|
|
os[1] = NoBaseNoMember(1);
|
|
|
|
std::vector<std::string> expectedCallStack{
|
|
"NoBaseNoMember::NoBaseNoMember()",
|
|
"NoBaseNoMember::NoBaseNoMember()",
|
|
"NoBaseNoMember::NoBaseNoMember(int)",
|
|
"NoBaseNoMember::~NoBaseNoMember()",
|
|
"NoBaseNoMember::NoBaseNoMember(int)",
|
|
"NoBaseNoMember::~NoBaseNoMember()",
|
|
};
|
|
//assert(callStack == expectedCallStack);
|
|
}
|
|
|
|
/*
|
|
Faster because does not call default constructors and extra destructors.
|
|
*/
|
|
{
|
|
callStack.clear();
|
|
|
|
NoBaseNoMember os[] = {NoBaseNoMember(0), NoBaseNoMember(1)};
|
|
|
|
std::vector<std::string> expectedCallStack = {
|
|
"NoBaseNoMember::NoBaseNoMember(int)",
|
|
"NoBaseNoMember::NoBaseNoMember(int)",
|
|
};
|
|
assert(callStack == expectedCallStack);
|
|
}
|
|
|
|
/*
|
|
If constructors take a single argument, conversions are made explicitly,
|
|
and we can write even less useless code.
|
|
*/
|
|
{
|
|
NoBaseNoMember os[] = {0, 1};
|
|
}
|
|
|
|
/*
|
|
In C++11, it is also possible to initialize objects that take more than two arguments
|
|
via uniform initialization.
|
|
*/
|
|
{
|
|
Class cs[] = {{0, 1}, {2, 3}};
|
|
}
|
|
|
|
/*
|
|
# memset
|
|
|
|
Like many C functions, memset does not work with objects, because objects
|
|
may contain extra data such as a VTABLE.
|
|
*/
|
|
if (0) {
|
|
Class *var = new Class;
|
|
std::memset(var, 0, sizeof(Class));
|
|
}
|
|
}
|
|
|
|
/*
|
|
Member class constructors are called before outter class in declaration order.
|
|
|
|
Member class destructors are called after outter class in reverse declaration order.
|
|
*/
|
|
{
|
|
callStack.clear();
|
|
|
|
{
|
|
MemberConstructorTest o;
|
|
}
|
|
|
|
std::vector<std::string> expectedCallStack =
|
|
{
|
|
"NoBaseNoMember0::NoBaseNoMember0()",
|
|
"NoBaseNoMember1::NoBaseNoMember1()",
|
|
"MemberConstructorTest::MemberConstructorTest()",
|
|
"MemberConstructorTest::~MemberConstructorTest()",
|
|
"NoBaseNoMember1::~NoBaseNoMember1()",
|
|
"NoBaseNoMember0::~NoBaseNoMember0()",
|
|
};
|
|
assert(callStack == expectedCallStack);
|
|
}
|
|
|
|
// # static fields
|
|
{
|
|
{
|
|
Class c, c1;
|
|
int i;
|
|
c.iStatic = 0;
|
|
assert(Class::iStatic == 0);
|
|
c1.iStatic = 1;
|
|
assert(Class::iStatic == 1);
|
|
Class::iStatic = 2;
|
|
assert(Class::iStatic == 2);
|
|
}
|
|
|
|
{
|
|
Class c;
|
|
c.staticMethod();
|
|
Class::staticMethod();
|
|
}
|
|
}
|
|
|
|
/*
|
|
# temporary objects
|
|
|
|
Temporary objects are objects without a name that exist for short time on the stack.
|
|
|
|
May exist in C as an implmentation method for structs,
|
|
but their effect is not noticeable because there are no constructors or destructors in C.
|
|
*/
|
|
{
|
|
/*
|
|
Two constructors and *one destructor* called!
|
|
|
|
Operation order:
|
|
|
|
- `NoBaseNoMember c;` calls a constructor
|
|
- `NoBaseNoMember();` calls a constructor of a temporary object
|
|
- assignment is made
|
|
- the object created by `NoBaseNoMember();` goes out of scope and is destroyed
|
|
|
|
Therefore the following may be more effecitive due to copy elision:
|
|
|
|
NoBaseNoMember c = NoBaseNoMember();
|
|
|
|
in which case only a single constructor is called.
|
|
Copy elision in this case is widely implemented.
|
|
*/
|
|
{
|
|
callStack.clear();
|
|
|
|
NoBaseNoMember c; //1 constructor
|
|
c = NoBaseNoMember(); //1 constructor of the temporary, 1 assign, 1 destructor of the temporary
|
|
|
|
std::vector<std::string> expectedCallStack =
|
|
{
|
|
"NoBaseNoMember::NoBaseNoMember()",
|
|
"NoBaseNoMember::NoBaseNoMember()",
|
|
"NoBaseNoMember::operator=",
|
|
"NoBaseNoMember::~NoBaseNoMember()",
|
|
};
|
|
assert(callStack == expectedCallStack);
|
|
}
|
|
|
|
/*
|
|
Methods of temporaries can be called.
|
|
|
|
Constructor and destructor are called, so this is not very efficient,
|
|
and a static method would probably be better in this case.
|
|
*/
|
|
{
|
|
callStack.clear();
|
|
NoBaseNoMember().method();
|
|
std::vector<std::string> expectedCallStack =
|
|
{
|
|
"NoBaseNoMember::NoBaseNoMember()",
|
|
"NoBaseNoMember::method()",
|
|
"NoBaseNoMember::~NoBaseNoMember()",
|
|
};
|
|
assert(callStack == expectedCallStack);
|
|
}
|
|
|
|
/*
|
|
Cannot get address of a temporary on current scope
|
|
as it will certainly go out of scope and leave a dangling reference.
|
|
*/
|
|
{
|
|
Class c = Class();
|
|
Class* cp = &c;
|
|
//cp = &Class();
|
|
}
|
|
|
|
/*
|
|
Temporaries can be passed to functions.
|
|
|
|
This is essentially the same as passing them to copy constructors or assigns.
|
|
|
|
This is valid because the temporary object is valid until the end of the full expression
|
|
in which it is created; that is, until after the function call returns.
|
|
|
|
Temporaries can be passed by address only as const parameters of functions.
|
|
TODO why? Modifying it for return makes no sense, but why not usint it as a buffer?
|
|
isn't its lifetime longer than the function call? Is this related to const lifetime lenghening?
|
|
*/
|
|
{
|
|
NoBaseNoMember b;
|
|
NoBaseNoMember::temporaryReference(b);
|
|
//NoBaseNoMember::temporaryReference(NoBaseNoMember());
|
|
NoBaseNoMember::temporaryReferenceConst(NoBaseNoMember());
|
|
}
|
|
}
|
|
|
|
/*
|
|
# copy and assign constructors
|
|
|
|
The difference is that:
|
|
|
|
- copy is a way to initialize a new object
|
|
- assign is a way to modify an existing object to ressemble another
|
|
|
|
The implicitly defined constructors might not do what you want, specially when you
|
|
allocate memory inside the constructor! See the Rule of Three.
|
|
|
|
Implicilty Default copy and assign is probably exist in order to allow class parameter passing to functions.
|
|
|
|
- <http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom>
|
|
- <http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three>
|
|
*/
|
|
{
|
|
//every class has a default copy operator and assign constructor
|
|
{
|
|
DefaultCopyAssignCtor c0(0);
|
|
DefaultCopyAssignCtor c1(1);
|
|
|
|
//assign operator
|
|
c0 = c1;
|
|
assert(c0.i == c1.i);
|
|
|
|
//copy constructor
|
|
DefaultCopyAssignCtor c2(c0);
|
|
assert(c2.i == c0.i);
|
|
|
|
//there are still two separate copies of the object
|
|
c0.i = 0;
|
|
c1.i = 1;
|
|
assert(c0.i == 0);
|
|
}
|
|
|
|
// # copy constructor
|
|
{
|
|
NoBaseNoMember c(1);
|
|
|
|
//explicity copy notation
|
|
{
|
|
callStack.clear();
|
|
NoBaseNoMember c1(c);
|
|
std::vector<std::string> expectedCallStack =
|
|
{
|
|
"NoBaseNoMember::NoBaseNoMember(NoBaseNoMember)",
|
|
};
|
|
assert(callStack == expectedCallStack);
|
|
assert(c1.i == 1);
|
|
}
|
|
|
|
/*
|
|
Same as above.
|
|
|
|
*COPY CONSTRUCTOR CALLED, NOT ASSIGN CONSTRUCTOR*
|
|
because object is being created
|
|
|
|
On C++11, move constructor will be called if rhs is a rvalue.
|
|
*/
|
|
{
|
|
callStack.clear();
|
|
NoBaseNoMember c1 = c;
|
|
std::vector<std::string> expectedCallStack =
|
|
{
|
|
"NoBaseNoMember::NoBaseNoMember(NoBaseNoMember)",
|
|
};
|
|
assert(callStack == expectedCallStack);
|
|
assert(c1.i == 1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
There is no default copy constructor/assign operator inherited from base clases,
|
|
you must write one yourself.
|
|
*/
|
|
{
|
|
Base b;
|
|
Class c(b);
|
|
}
|
|
|
|
/*
|
|
It is possible to assing / copy from derived to base class.
|
|
*/
|
|
{
|
|
Class c;
|
|
c.Base::i = 1;
|
|
Base b(c);
|
|
assert(b.i == 1);
|
|
}
|
|
|
|
/*
|
|
# equality operator for classes
|
|
|
|
There is no default `==` operator for classes.
|
|
|
|
You must define your own.
|
|
*/
|
|
{
|
|
NoEquality c0;
|
|
NoEquality c1;
|
|
|
|
//ERROR no match for operator ==
|
|
//assert(c0 == c1);
|
|
}
|
|
|
|
/*
|
|
# rule of three
|
|
|
|
If you need to implement either of (to deal with dynamic allocation):
|
|
|
|
- destructor
|
|
- assignment =
|
|
- copy constructor
|
|
|
|
It is likely that you need to implement all the three.
|
|
|
|
In that case, you should use the copy and swap idiom.
|
|
*/
|
|
|
|
/*
|
|
# copy and swap idom
|
|
|
|
The best way to implement the rule of three:
|
|
|
|
- without code duplication
|
|
- with exception type safety
|
|
|
|
Great explanation: <http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom>
|
|
|
|
Why swap should be afriend: <http://stackoverflow.com/questions/5695548/public-friend-swap-member-function>
|
|
*/
|
|
{
|
|
CopyAndSwap c0(2, 2);
|
|
CopyAndSwap c1(3, 3);
|
|
|
|
//assign
|
|
//c0 = c1;
|
|
//assert(c0);
|
|
|
|
//assign
|
|
//CopyAndSwap c2(c0);
|
|
}
|
|
|
|
#if __cplusplus >= 201103L
|
|
/*
|
|
# #rvalue reference
|
|
|
|
<http://www.artima.com/cppsource/rvalue.html>
|
|
|
|
C++11
|
|
|
|
New type of reference.
|
|
|
|
Old references are referred to as lvalue references, since they must be initialized by lvaues.
|
|
|
|
Denoted by double ampersand `&&`.
|
|
|
|
There is one difference between them and lvalue references:
|
|
rvalue references can only be initialized by both rvalues,
|
|
unlike lvalue references which can only be initialized by lvalues
|
|
(except if they are const).
|
|
|
|
Main motivation: implement move semantics.
|
|
*/
|
|
{
|
|
|
|
/*
|
|
Cannot be bound to an lvalue on stack.
|
|
|
|
This is the *key* property of rvalue references, since it allows function overload
|
|
to differentiate lvalues from rvalues, and thus implement move contructors.
|
|
*/
|
|
{
|
|
int i = 0;
|
|
|
|
int&& irr = 1;
|
|
|
|
// ERROR: i is not rvalue, it is a lvalue!
|
|
//int&& irrBad = i;
|
|
}
|
|
|
|
// On all other aspects besides initialization, rvalue references
|
|
// are identical to lvalue references.
|
|
{
|
|
int&& irr = 0;
|
|
assert(irr == 0);
|
|
|
|
irr = 1;
|
|
assert(irr == 1);
|
|
|
|
//once assigned, rvalue references are iden
|
|
std::cout << "&iff = " << &irr << std::endl;
|
|
}
|
|
|
|
// Can function overload based on rvalue or lvalue.
|
|
// This is essential for move semantics.
|
|
{
|
|
int i;
|
|
assert(overloadRLvalue(i) == "lval");
|
|
assert(overloadRLvalue(1) == "rval");
|
|
}
|
|
}
|
|
|
|
/*
|
|
# xvalue
|
|
|
|
# glvalue
|
|
|
|
# prvalue
|
|
|
|
In addition to the C99 rvalues and lvalues,
|
|
the C++11 standard defines new concepts:
|
|
|
|
- xvalue
|
|
- glvalue
|
|
- prvalue
|
|
|
|
<http://stackoverflow.com/questions/3601602/what-are-rvalues-lvalues-xvalues-glvalues-and-prvalues>
|
|
|
|
This is probably a consequence of move semantincs.
|
|
|
|
*/
|
|
|
|
/*
|
|
# move constructor
|
|
|
|
Constructor that takes rvalues instead of lvalues.
|
|
|
|
Used to implement move semantics.
|
|
|
|
# move semantics
|
|
|
|
Useful in situtations where a class manages dynamic data.
|
|
|
|
Basic idea: when copying from an rvalue, it is not necessary to make an expensive copy of it:
|
|
it suffices to acquire its data via swap, and leave it on a valid state (via a default constructor for example).
|
|
|
|
This is true because the rvalue passed to a copy constructor cannot be seen.
|
|
|
|
Value reference allows to overload the copy constructor based not on type,
|
|
but on the fact that a value is an rvalue or an lvalue!
|
|
|
|
No change must be done to the copy and swap idiom for move semantics to work for the assigment operator,
|
|
since in C++11 `int i = rvale` calls a move consttuctor on `i` while `int i = lvalue` calls a copy constructor.
|
|
|
|
<http://stackoverflow.com/questions/3106110/what-is-move-semantics>
|
|
*/
|
|
{
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
# as-if rule
|
|
|
|
<http://en.cppreference.com/w/cpp/language/as_if>
|
|
|
|
Rule that specifies that compilers can optimize any behaviour that is not fixed by the standard.
|
|
|
|
The following are specified:
|
|
|
|
- Accesses (reads and writes) to the volatile objects occur in the same order as written.
|
|
|
|
- At program termination, the data written to all files is exactly as if the program was executed as written.
|
|
|
|
- All input and output operations occur in the same order and with the same content
|
|
as if the program was executed as written.
|
|
|
|
The only exception to the ruls is copy elision.
|
|
*/
|
|
|
|
/*
|
|
# copy elision
|
|
|
|
- http://en.cppreference.com/w/cpp/language/copy_elision
|
|
- http://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization
|
|
|
|
Exceptions to the as-if rules, which specifies cases in which compilers
|
|
may reduce the number of copy operations made, which is detectable in C++'
|
|
because of possible side effects constructors and destructors (such as printing to stdout
|
|
or modifying a global std::vector).
|
|
*/
|
|
{
|
|
/*
|
|
# temporary copy elision
|
|
|
|
If no copy elision is done:
|
|
|
|
1. temporary object constructor
|
|
2. copy temporary to c
|
|
3. temporary object destructor
|
|
|
|
If copy elision is done:
|
|
|
|
1. c is constructed directly.
|
|
|
|
Therefore both results are possible and the result is unpredictable:
|
|
|
|
std::vector<std::string> expectedCallStack = {
|
|
"NoBaseNoMember::NoBaseNoMember()",
|
|
};
|
|
|
|
std::vector<std::string> expectedCallStack = {
|
|
"NoBaseNoMember::NoBaseNoMember()",
|
|
"NoBaseNoMember::~NoBaseNoMember()",
|
|
};
|
|
|
|
assert(callStack == expectedCallStack);
|
|
*/
|
|
{
|
|
{
|
|
callStack.clear();
|
|
NoBaseNoMember c = NoBaseNoMember();
|
|
std::cout << "temporary copy elision" << std::endl;
|
|
for (auto s : callStack) std::cout << " " << s << std::endl;
|
|
}
|
|
|
|
{
|
|
callStack.clear();
|
|
NoBaseNoMember c;
|
|
c = NoBaseNoMember();
|
|
std::cout << "no temporary copy elision" << std::endl;
|
|
for (auto s : callStack) std::cout << " " << s << std::endl;
|
|
}
|
|
}
|
|
|
|
/*
|
|
# RVO
|
|
|
|
Return value optimization.
|
|
|
|
Like in C, when a function returns an object, the compiler adds a hidden pointer
|
|
to the function.
|
|
|
|
Ex: definition
|
|
|
|
static NoBaseNoMember create()
|
|
{
|
|
return NoBaseNoMember();
|
|
}
|
|
|
|
gets converted to:
|
|
|
|
static create(NoBaseNoMember* hiddenTemp)
|
|
{
|
|
//1 constructor, 1 copy, 1 destructor if no temporary copy elision
|
|
//1 constructor if temporary copy elision
|
|
*hiddenPtr = NoBaseNoMember();
|
|
}
|
|
|
|
And calls:
|
|
|
|
c = NoBaseNoMember::create();
|
|
|
|
Get converted to either:
|
|
|
|
NoBaseNoMember hiddenTemp; //1 constructor call
|
|
NoBaseNoMember::create(&hiddenTemp);
|
|
s = temp; //1 copy
|
|
//1 destructor for the temporary object
|
|
|
|
If no RVO was made, giving:
|
|
|
|
- 2 constructors
|
|
- 1 or 2 copies
|
|
- 1 or 2 destructors
|
|
|
|
or simply:
|
|
|
|
getNoBaseNoMember(&s);
|
|
|
|
if RVO is made which adds up to:
|
|
|
|
- 1 constructor
|
|
- 0 or 1 copies
|
|
- 1 destructor
|
|
*/
|
|
{
|
|
NoBaseNoMember c;
|
|
callStack.clear();
|
|
|
|
c = NoBaseNoMember::create();
|
|
std::cout << "RVO" << std::endl;
|
|
for (auto s : callStack) std::cout << " " << s << std::endl;
|
|
}
|
|
|
|
/*
|
|
# NRVO
|
|
|
|
Named RVO.
|
|
|
|
Like RVO, but harder to make since takes a named object instead of a temporary return value,
|
|
that is:
|
|
|
|
NoBaseNoMember c;
|
|
return c
|
|
|
|
instead of:
|
|
|
|
return NoBaseNoMember();
|
|
|
|
In many cases this cannot be done, and it is hard or impossible for the compiler to optimize this.
|
|
*/
|
|
{
|
|
/* should be possible if the compiler is smart enough */
|
|
{
|
|
NoBaseNoMember c;
|
|
callStack.clear();
|
|
c = NoBaseNoMember::createNrvo();
|
|
std::cout << "NRVO" << std::endl;
|
|
for (auto s : callStack) std::cout << " " << s << std::endl;
|
|
}
|
|
|
|
/*
|
|
TODO0 why do I get:
|
|
|
|
NoBaseNoMember::NoBaseNoMember(int)
|
|
NoBaseNoMember::NoBaseNoMember(int)
|
|
NoBaseNoMember::NoBaseNoMember(NoBaseNoMember) //copy from temporary to C
|
|
NoBaseNoMember::~NoBaseNoMember() //destructor for the temporary
|
|
NoBaseNoMember::~NoBaseNoMember() //destructor for 0
|
|
NoBaseNoMember::~NoBaseNoMember() //destructor for 1
|
|
|
|
- where is the constructor of the temporary object?
|
|
*/
|
|
{
|
|
NoBaseNoMember c;
|
|
callStack.clear();
|
|
c = NoBaseNoMember::createNrvoHard();
|
|
std::cout << "NRVO hard" << std::endl;
|
|
for (auto s : callStack) std::cout << " " << s << std::endl;
|
|
}
|
|
}
|
|
|
|
/*
|
|
# exception copy elision
|
|
*/
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
# Inheritance
|
|
*/
|
|
{
|
|
/*
|
|
# Override
|
|
|
|
Means to implement a method on the derived class, replacing the definition on the base class.
|
|
*/
|
|
{
|
|
Class c;
|
|
Class* cp = &c;
|
|
|
|
c.i = 0;
|
|
c.Class::i = 0;
|
|
cp->Class::i = 0;
|
|
c.Base::i = 1;
|
|
c.BaseAbstract::i = 2;
|
|
|
|
assert(c.i == 0);
|
|
assert(c.Class::i == 0);
|
|
assert(cp->Class::i == 0);
|
|
|
|
assert(c.Base::i == 1);
|
|
assert(cp->Base::i == 1);
|
|
|
|
assert(c.BaseAbstract::i == 2);
|
|
assert(cp->BaseAbstract::i == 2);
|
|
|
|
// ERROR: ambiguous
|
|
//c.iAmbiguous = 0;
|
|
c.Base::iAmbiguous = 0;
|
|
c.BaseAbstract::iAmbiguous = 0;
|
|
|
|
callStack.clear();
|
|
c.method();
|
|
assert(callStack.back() == "Class::method()");
|
|
// ERROR: ambiguous
|
|
//c.methodAmbiguous();
|
|
callStack.clear();
|
|
c.Base::methodAmbiguous();
|
|
assert(callStack.back() == "Base::methodAmbiguous()");
|
|
|
|
callStack.clear();
|
|
c.BaseAbstract::methodAmbiguous();
|
|
assert(callStack.back() == "BaseAbstract::methodAmbiguous()");
|
|
}
|
|
|
|
/*
|
|
Inheritance and overloading.
|
|
|
|
You cannot overload an inherited method directly
|
|
|
|
http://stackoverflow.com/questions/72010/c-overload-resolution
|
|
|
|
TODO why is that using required? What is the advantage?
|
|
*/
|
|
{
|
|
InheritOverloadDerived c;
|
|
c.overload();
|
|
}
|
|
|
|
#if __cplusplus >= 201103L
|
|
/*
|
|
# inheriting constructors
|
|
|
|
Reuse base class constructors: <http://stackoverflow.com/questions/8093882/using-c-base-class-constructors>
|
|
is possible "automatically" only in C++11 (using `using`).
|
|
|
|
Before C++11, is was necessary to call each constructor explicitly and forward the argments.
|
|
|
|
Only implemented in G++ 4.8. -std=c++11 flag available since G++ 4.7.
|
|
*/
|
|
{
|
|
InheritingCtorDerived c0;
|
|
assert(c0.i == 0);
|
|
InheritingCtorDerived c1(1);
|
|
InheritingCtorDerived c2(c0);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
# virtual
|
|
|
|
Virtual: decides on runtime based on object type.
|
|
|
|
<http://stackoverflow.com/questions/2391679/can-someone-explain-c-virtual-methods>
|
|
|
|
# Pure virtual function
|
|
|
|
Cannot instantiate this class
|
|
|
|
Can only instantiate derived classes that implement this.
|
|
|
|
If a class has a pure virtual method is called as an *abstract class* or *interface*.
|
|
|
|
In Java there is a language difference between those two terms,
|
|
and it might be a good idea to differentiate them when speaking about C++:
|
|
|
|
- interface: no data
|
|
- abstract: data
|
|
|
|
# Polymorphism
|
|
|
|
- loop an array of several dereived classes
|
|
- call a single base class method
|
|
- uses the correct derived override
|
|
|
|
Implementation: *vtable* is used to implement this.
|
|
|
|
# vtable
|
|
|
|
<http://en.wikipedia.org/wiki/Virtual_method_table>
|
|
|
|
Whenever you create a pointer to a class with a virtual method,
|
|
that pointer points to a pointer that identifies the class type,
|
|
and points to the correct method.
|
|
|
|
Consequence: every call to a virtual methods means:
|
|
|
|
- an extra pointer dereference
|
|
- an extra pointer stored in memory
|
|
|
|
Also virtual functions cannot be inlined.
|
|
|
|
# Static interfaces
|
|
|
|
It is possible to assert that interfaces are implemented without dynamic vtable overhead via CRTP:
|
|
|
|
- <http://stackoverflow.com/questions/2587541/does-c-have-a-static-polymorphism-implementation-of-interface-that-does-not-us>
|
|
|
|
- <http://en.wikipedia.org/wiki/Template_metaprogramming#Static_polymorphism>
|
|
|
|
# CRTP
|
|
|
|
Curiously recurring template pattern.
|
|
|
|
<http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern#Static_polymorphism>
|
|
*/
|
|
{
|
|
// ERROR: BaseAbstract cannot be instantiated because it contains a pure virtual method
|
|
// virtual = 0;. That method must be implemented on derived classes
|
|
//BaseAbstract b;
|
|
|
|
// Even if you can't instantiate base, you can have pointers to it.
|
|
{
|
|
BaseAbstract* bap = new Class;
|
|
// SAME:
|
|
//BaseAbstract* bap = &c;
|
|
|
|
callStack.clear();
|
|
bap->method();
|
|
// Base method because non-virtual.
|
|
assert(callStack.back() == "BaseAbstract::method()");
|
|
|
|
callStack.clear();
|
|
bap->virtualMethod();
|
|
// Class method because virtual.
|
|
assert(callStack.back() == "Class::virtualMethod()");
|
|
|
|
delete bap;
|
|
}
|
|
|
|
// You can also have BaseAbstract&.
|
|
{
|
|
Class c;
|
|
BaseAbstract& ba = c;
|
|
|
|
callStack.clear();
|
|
ba.method();
|
|
assert(callStack.back() == "BaseAbstract::method()");
|
|
|
|
callStack.clear();
|
|
ba.virtualMethod();
|
|
assert(callStack.back() == "Class::virtualMethod()");
|
|
}
|
|
|
|
{
|
|
Class c = Class();
|
|
Base* bp = &c;
|
|
bp = bp->covariantReturn();
|
|
|
|
callStack.clear();
|
|
bp->virtualMethod();
|
|
assert(callStack.back() == "Class::virtualMethod()");
|
|
|
|
// ERROR: conversion from Base to Class
|
|
//classPtr = basePtr->covariantReturn();
|
|
}
|
|
|
|
/*
|
|
It is not possibleto implement pure virtual methods on another base class:
|
|
they must be implemented on the Derived class.
|
|
*/
|
|
{
|
|
//DerivedAbtractAndImplementator d; //ERROR
|
|
}
|
|
|
|
// Call virtual method from base constructor: http://stackoverflow.com/questions/496440/c-virtual-function-from-constructor?lq=1
|
|
// Not possible because derived class has not yet been initialized.
|
|
// Workaround? http://www.parashift.com/c%2B%2B-faq-lite/calling-virtuals-from-ctor-idiom.html
|
|
{
|
|
{
|
|
VirtualFromCtorDerived c;
|
|
assert(c.i == 0);
|
|
}
|
|
|
|
// The simplest thing to do seems to be to define a separate init function.
|
|
// Downside: requires you to write a new constructor on the derived, and forward all argments.
|
|
{
|
|
VirtualFromCtor2PhaseDerived c;
|
|
assert(c.i == 1);
|
|
assert(c.j == 10);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
# multiple inheritance
|
|
|
|
In C++, if a member of an object or static variable of a class
|
|
comes from two base classes, an ambiguity occurs and the program does not
|
|
compile.
|
|
|
|
This just makes multiple inheritance very insane, since the addition of
|
|
new fields in a Base class can break existing code on Derived classes.
|
|
*/
|
|
{
|
|
//MultipleInheritanceConflictDerived::is;
|
|
//MultipleInheritanceConflictDerived().i;
|
|
//MultipleInheritanceConflictDerived().f();
|
|
}
|
|
|
|
/*
|
|
# dreaded diamond
|
|
|
|
# virtual inheritance
|
|
|
|
Solves the dreaded diamond problem.
|
|
|
|
Has nothing to do with the `virtual` keyword for methods:
|
|
everything is done at compile time in this usage.
|
|
|
|
<http://stackoverflow.com/questions/21558/in-c-what-is-a-virtual-base-class>
|
|
*/
|
|
}
|
|
|
|
// # friend
|
|
{
|
|
Friend f(1);
|
|
FriendOfFriend ff(2);
|
|
|
|
assert(friendGetI(f) == f.getI());
|
|
assert(friendGetIInnerDefine(f) == f.getI());
|
|
assert(ff.getFriendI(f) == f.getI());
|
|
}
|
|
|
|
// # nested classes
|
|
{
|
|
Base::Nested baseNested;
|
|
Base::Nested2 baseNested2;
|
|
}
|
|
|
|
// # nested typedefs
|
|
{
|
|
Base::NESTED_INT i = 1;
|
|
// ERROR: is private
|
|
//Base::PRIVATE_NESTED_INT j = 1;
|
|
}
|
|
}
|
|
|
|
/*
|
|
# struct
|
|
|
|
Structs in C++ are very similar to classes: support access modifiers,
|
|
inheritance, constructors, templates, etc.
|
|
|
|
The major difference between them is that the default access modifier for structs
|
|
is public, while for classes it is private.
|
|
|
|
This is why structs are used on many simple short language examples:
|
|
no public line is needed.
|
|
|
|
The Google C++ style guide recommends using struct only if there is no constructors,
|
|
and classes otherwise.
|
|
|
|
<http://stackoverflow.com/questions/2750270/c-c-struct-vs-class>
|
|
*/
|
|
{
|
|
struct DerivedStruct s(1);
|
|
assert(s.i == 1);
|
|
}
|
|
|
|
/*
|
|
# RTTI
|
|
|
|
Run time type information.
|
|
|
|
Any function that gets class information explicitly at runtime:
|
|
|
|
- `typeid`
|
|
- `dynamic_cast`
|
|
|
|
Google style 3.26 discourages this, since if you really need it your design is probably flawed.
|
|
|
|
Also using typeid on variables means that extra meta data must be kept about those variables.
|
|
*/
|
|
|
|
/*
|
|
# typeid
|
|
|
|
Get type of variables
|
|
|
|
Can be done for both types and variables of the type.
|
|
|
|
Returns objects of `type_info`
|
|
|
|
# type_info
|
|
|
|
Type returned by `typeid`.
|
|
*/
|
|
{
|
|
// typeid returns `type_info`.
|
|
//
|
|
// However copy and assign for type_info are private,
|
|
// so the following fails.
|
|
{
|
|
//std::type_info t = typeid(int);
|
|
//std::type_info t(typeid(int));
|
|
}
|
|
|
|
// type_info implements `==` and `!=`.
|
|
//
|
|
// typeid's of different types are always different.
|
|
{
|
|
int i, i1;
|
|
int& ia = i;
|
|
Class c;
|
|
|
|
assert(typeid(i) == typeid(int) );
|
|
assert(typeid(ia) == typeid(int&));
|
|
assert(typeid(i) == typeid(i1) );
|
|
assert(typeid(i) != typeid(c) );
|
|
}
|
|
|
|
// name: returns a string representation of the type.
|
|
//
|
|
// The exact string is implementation defined.
|
|
{
|
|
std::cout << "typeid(int).name() = " << typeid(int).name() << std::endl;
|
|
}
|
|
|
|
// before: <http://stackoverflow.com/questions/8682582/what-is-type-infobefore-useful-for>
|
|
// hash_code: return a size_t hash of the type
|
|
}
|
|
|
|
/*
|
|
# type_index
|
|
|
|
Wrapper around type_info that allows copy and assign.
|
|
*/
|
|
{
|
|
std::type_index t = typeid(int);
|
|
}
|
|
|
|
/*
|
|
# type_traits
|
|
|
|
<http://www.cplusplus.com/reference/type_traits/>
|
|
*/
|
|
{
|
|
}
|
|
|
|
/*
|
|
# typecast
|
|
|
|
Sources:
|
|
|
|
- <http://www.cplusplus.com/doc/tutorial/typecasting/>
|
|
- <http://stackoverflow.com/questions/28002/regular-cast-vs-static-cast-vs-dynamic-cast>
|
|
- <http://stackoverflow.com/questions/332030/when-should-static-cast-dynamic-cast-and-reinterpret-cast-be-used>
|
|
*/
|
|
{
|
|
/*
|
|
Implicit typecast.
|
|
|
|
Works if types are convertible, either by the compiler or by a constructor that takes one single argument.
|
|
*/
|
|
{
|
|
//convertible basetypes
|
|
//same as in C
|
|
{
|
|
int i = 0.25;
|
|
assert(i == 0);
|
|
}
|
|
|
|
//via constructor that takes a single argument and is not explicit
|
|
//works becaues the constructor NoBaseNoMember(int) exists
|
|
{
|
|
NoBaseNoMember c = 1;
|
|
assert(c.i == 1);
|
|
}
|
|
|
|
/*
|
|
# explicit
|
|
|
|
Keyword specifies that a given constructor can only be used explicitly.
|
|
*/
|
|
{
|
|
// ERROR:
|
|
//ExplicitCtor c = 1;
|
|
}
|
|
}
|
|
|
|
/*
|
|
# explicit typecast
|
|
*/
|
|
{
|
|
/*
|
|
# c style typecast
|
|
|
|
TODO what does it do in relation to the others? why should it not be used?
|
|
*/
|
|
|
|
/*
|
|
# dynamic_cast
|
|
|
|
- done at runtime
|
|
- only for pointers or references
|
|
- can only be done from / to base derived
|
|
|
|
- always works for derived to base
|
|
|
|
- baes to derived:
|
|
|
|
- compiles only for polymorphic classes
|
|
|
|
- a runtime check is done to see if the cast is correct or an exception is thrown
|
|
*/
|
|
{
|
|
}
|
|
|
|
/*
|
|
# static_cast
|
|
|
|
- done at compile time
|
|
- only for pointers or references
|
|
- can only be done from / to base derived.
|
|
|
|
Always compiles, but if the conversion is wrong, bad errors may happen at runtime.
|
|
*/
|
|
|
|
/*
|
|
# reinterpret_cast
|
|
|
|
Converts anything to anything by copying bytes.
|
|
|
|
Behaviour is not portable in general.
|
|
*/
|
|
|
|
/*
|
|
# const_cast
|
|
|
|
Change (add/remove) constantness and volatility of objects (property called cv-qualification).
|
|
|
|
TODO when should it be used?
|
|
|
|
<http://stackoverflow.com/questions/357600/is-const-cast-safe/357640#357640>
|
|
*/
|
|
{
|
|
//remove const
|
|
{
|
|
const int i = 0;
|
|
int const * ip = &i;
|
|
|
|
*const_cast<int*>(ip) = 1;
|
|
//assert(i == 1);
|
|
//TODO why fail?
|
|
|
|
}
|
|
|
|
// ERROR: Returns rvalues. Therefore cannot initialize non-const references.
|
|
{
|
|
int i = 0;
|
|
int *ip;
|
|
//const int*& ipa = const_cast<const int*>(ip);
|
|
//ipa is a non const reference.
|
|
//int *const& would be a const reference.
|
|
}
|
|
|
|
// ERROR: only has effect for a single statement
|
|
{
|
|
//const_cast<int*>(ip);
|
|
//*ip = 1;
|
|
}
|
|
|
|
// ERROR: only works for pointers
|
|
{
|
|
const int i = 0;
|
|
//const_cast<int>(i) = 1;
|
|
}
|
|
}
|
|
|
|
// Function pointer typecast.
|
|
{
|
|
// Required when a function is overloaded, and you want to use a function pointer.
|
|
// TODO understand syntax.
|
|
{
|
|
std::string s = "a,bc. d";
|
|
auto end = s.end();
|
|
s.erase(std::remove_if(s.begin(), end, (int(*)(int))std::ispunct), end);
|
|
std::cout << s << std::endl;
|
|
assert(s == "abc d");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
# dynamic memory
|
|
|
|
C++ replaces C's malloc and free with new and delete.
|
|
|
|
It is very rare to need explicit dynamic allocation. Always use:
|
|
|
|
std::vector<int> is(n)
|
|
|
|
instead of:
|
|
|
|
int *is = new int[n];
|
|
|
|
and `vector<int>(n)` is as efficient and much more flexible than `new int[N]`.
|
|
|
|
Dynamic allocation is a dangerous, and it may lead to hard to debug memory leaks.
|
|
|
|
Always encapsulate dynamic allocation inside class constructors,
|
|
and free it the destructor, like `std::vector` does.
|
|
|
|
Never use C style malloc on C++ code. `new` works better with classes.
|
|
|
|
# new
|
|
|
|
Allocate dynamic memory.
|
|
|
|
Throw `std::bad_alloc` in case of error.
|
|
|
|
# realloc
|
|
|
|
There is no direct replacement to realloc or calloc as of C++11
|
|
<http://stackoverflow.com/questions/3482941/how-do-you-realloc-in-c>
|
|
*/
|
|
{
|
|
/*
|
|
basic usage with proper error checking
|
|
*/
|
|
{
|
|
int* ip;
|
|
try {
|
|
ip = new int[5];
|
|
} catch(std::bad_alloc& ba) {
|
|
assert(false);
|
|
}
|
|
ip[0] = 1;
|
|
delete[] ip;
|
|
}
|
|
|
|
/*
|
|
# delete
|
|
|
|
Free memory allocatedby `new`.
|
|
|
|
Just like C `free`:
|
|
|
|
- deleting a `NULL` does nothing.
|
|
- deleting any other pointer twice can lead to memory corruption
|
|
- deleting a pointer which was not dynamically allocated can lead to memory curruption
|
|
|
|
Destructor of object pointed to is called.
|
|
|
|
A common technique is to set a pointer to `NULL` after it is deleted,
|
|
to avoid deleting a pointer twice:
|
|
<stackoverflow.com/questions/4190703/is-it-safe-to-delete-a-null-pointer>
|
|
|
|
An even better techinque may be to use smart pointers and containers.
|
|
*/
|
|
{
|
|
delete (int*)NULL;
|
|
delete[] (int*)NULL;
|
|
|
|
//delete NULL;
|
|
// WARN: cannot delete an integer type
|
|
|
|
//delete (void*)NULL;
|
|
// WARN: cannot delete a void pointer
|
|
}
|
|
|
|
//allocate single object / base type
|
|
{
|
|
int* ip = new int;
|
|
*ip = 1;
|
|
delete ip;
|
|
}
|
|
|
|
//delete calls destructors of deleted objects
|
|
{
|
|
callStack.clear();
|
|
NoBaseNoMember* cp = new NoBaseNoMember;
|
|
//NoBaseNoMember* cp = new NoBaseNoMember();
|
|
//SAME
|
|
assert(callStack.back() == "NoBaseNoMember::NoBaseNoMember()");
|
|
|
|
cp->method();
|
|
|
|
callStack.clear();
|
|
delete cp;
|
|
assert(callStack.back() == "NoBaseNoMember::~NoBaseNoMember()");
|
|
//calls destructor
|
|
}
|
|
|
|
{
|
|
callStack.clear();
|
|
NoBaseNoMember* cp = new NoBaseNoMember[2];
|
|
assert(callStack.back() == "NoBaseNoMember::NoBaseNoMember()"); callStack.pop_back();
|
|
assert(callStack.back() == "NoBaseNoMember::NoBaseNoMember()"); callStack.pop_back();
|
|
|
|
cp[0].method();
|
|
cp[1].method();
|
|
|
|
callStack.clear();
|
|
delete[] cp;
|
|
assert(callStack.back() == "NoBaseNoMember::~NoBaseNoMember()"); callStack.pop_back();
|
|
assert(callStack.back() == "NoBaseNoMember::~NoBaseNoMember()"); callStack.pop_back();
|
|
}
|
|
|
|
{
|
|
//int* ip = new int;
|
|
//delete ip;
|
|
//BAD
|
|
//undefined behavior, maybe crash
|
|
//delete ip;
|
|
}
|
|
|
|
{
|
|
//int* ip = new int;
|
|
//ip = new int;
|
|
//delete ip;
|
|
//BAD
|
|
//memory leak. memory is lost forever.
|
|
}
|
|
|
|
{
|
|
//int* ip;
|
|
//delete ip;
|
|
//BAD
|
|
//undefined behavior, maybe crash
|
|
//ip was not allocated after delete!
|
|
}
|
|
|
|
/*
|
|
# calloc
|
|
|
|
An analogue effect to calloc can be attained with *value-initialization*.
|
|
|
|
<http://stackoverflow.com/questions/808464/c-new-call-that-behaves-like-calloc>
|
|
*/
|
|
}
|
|
|
|
/*
|
|
# namespace
|
|
*/
|
|
{
|
|
//variables
|
|
{
|
|
int i;
|
|
i = 0; //inner i
|
|
::i = 0; //global i
|
|
namea::i = 0; //namea i
|
|
i++;
|
|
assert(i == 1);
|
|
assert(::i == 0);
|
|
assert(namea::i == 0);
|
|
|
|
f();
|
|
namea::f();
|
|
namea::nameaa::f();
|
|
}
|
|
|
|
/*
|
|
# using
|
|
|
|
Be very careful with `using`, because there is no way to unuse afterwards.
|
|
|
|
In particuar, *never* use `using namespace X` on the toplevel a header file,
|
|
or you shall confuse includers to tears.
|
|
*/
|
|
{
|
|
using namespace namea;
|
|
|
|
// ERROR ambiguous
|
|
//f();
|
|
//::f
|
|
//namea::f
|
|
|
|
::f();
|
|
namea::f();
|
|
namea::nameaa::f();
|
|
|
|
}
|
|
|
|
//in_namea_only = 1;
|
|
//brackets limit the using namespace scope
|
|
//It is obligatory to specify unused namespaces.
|
|
|
|
// ERROR: no namespace inside funcs
|
|
//namespace main{}
|
|
|
|
//namespace chaining
|
|
{
|
|
using namespace namea;
|
|
using namespace nameaa;
|
|
|
|
//f();
|
|
// ERROR ambiguous
|
|
//::f
|
|
//namea::f
|
|
//namea::nameaa:f
|
|
::f();
|
|
namea::f();
|
|
namea::nameaa::f();
|
|
}
|
|
|
|
//namespace alias
|
|
namespace newNamea = namea;
|
|
{
|
|
using namespace newNamea;
|
|
//f();
|
|
// ERROR: ambiguous.
|
|
//::f
|
|
//namea::f
|
|
}
|
|
|
|
//subimport
|
|
{
|
|
// Imports only name::f.
|
|
using namea::f;
|
|
|
|
f();
|
|
// OK: overwrides global f().
|
|
//namea::f
|
|
|
|
// ERROR: only f was imported.
|
|
//C c;
|
|
};
|
|
|
|
/*
|
|
# ADL
|
|
|
|
Argument dependent name lookup.
|
|
|
|
<http://en.wikipedia.org/wiki/Argument-dependent_name_lookup>
|
|
|
|
Allows for functions without namespace qualification:
|
|
|
|
- to be found
|
|
- to haves ambiguities resolved
|
|
|
|
based on the namespace in which the types of their arguments are defined.
|
|
|
|
Explains why operator `<<` does not need the `std::` qualifier,
|
|
even though *must* be implemented as a non-member function!!
|
|
(see info on operator overload for why)
|
|
|
|
ADL for operators is a major use case, because specifying namespaces
|
|
for operators completely destroys their eyecandy appeal.
|
|
*/
|
|
{
|
|
// ADL allows both to be found and differentiated!
|
|
{
|
|
{
|
|
struct adl0::s s;
|
|
assert(adl(s) == 0);
|
|
}
|
|
|
|
{
|
|
struct adl1::s s;
|
|
assert(adl(s) == 1);
|
|
}
|
|
}
|
|
|
|
// Only works if the type is defined on the same namespace as the function.
|
|
{
|
|
struct adl0::s s;
|
|
// ERROR: not declared on this scope
|
|
//assert(adl0FromAdl1(s) == 1);
|
|
}
|
|
|
|
// Works if at least one of the argument types is in the namespace.
|
|
{
|
|
struct adl0::s s;
|
|
assert(adlMultiArg(0, s, 1) == 0);
|
|
}
|
|
|
|
// Lookup works even if types from both namespaces are used.
|
|
{
|
|
struct adl0::s s0;
|
|
struct adl1::s s1;
|
|
assert(adl0And1FromAdl1(s0, s1) == 1);
|
|
}
|
|
|
|
// Of course, calls can still be ambiguous.
|
|
{
|
|
struct adl0::s s0;
|
|
struct adl1::s s1;
|
|
// ERROR: ambiguous call
|
|
//assert(adl01(s0, s1) == 0.5);
|
|
}
|
|
|
|
// Only works for *types* defined in the namespaces, not values.
|
|
{
|
|
//assert(adlNoType(adl0::i) == 0);
|
|
// ERROR: adlNoType not found on this scope
|
|
//assert(adlNoType(adl1::i) == 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
// # stdlib
|
|
{
|
|
// # string
|
|
{
|
|
// Initialize from string literal.
|
|
{
|
|
std::string s = "abc";
|
|
}
|
|
|
|
// cout works as expected.
|
|
{
|
|
std::string s = "abc";
|
|
std::stringstream oss;
|
|
oss << s;
|
|
assert(oss.str() == "abc");
|
|
}
|
|
|
|
/*
|
|
# + for strings
|
|
|
|
# cat
|
|
|
|
# concatenate.
|
|
|
|
Creates a new string.
|
|
|
|
The only way to do inline this without creating a new string seems to be by using stringstream.
|
|
http://stackoverflow.com/questions/662918/how-do-i-concatenate-multiple-c-strings-on-one-line
|
|
*/
|
|
{
|
|
std::string s = "ab";
|
|
std::string s1 = "cd";
|
|
assert(s + s1 == "abcd");
|
|
assert(s + "cd" == "abcd");
|
|
assert("cd" + s == "cdab");
|
|
}
|
|
|
|
// length
|
|
{
|
|
std::string s = "abc";
|
|
assert(s.length() == 3);
|
|
}
|
|
|
|
{
|
|
std::string s = "abc";
|
|
s[0] = 'A';
|
|
assert(s == "Abc");
|
|
|
|
// BAD: no born check! Compiles.
|
|
//s[3] = 'd';
|
|
}
|
|
|
|
/*
|
|
# lowercase
|
|
|
|
http://stackoverflow.com/questions/313970/stl-string-to-lower-case
|
|
*/
|
|
{
|
|
// Best stdlib way with transform:
|
|
std::string s = "AbCd1_";
|
|
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
|
|
assert(s == "abcd1_");
|
|
|
|
//Boost has a single function: boost::algorithm::to_lower(str);
|
|
}
|
|
|
|
/*
|
|
# c_str
|
|
|
|
Convert std::string to C null terminated char* string.
|
|
*/
|
|
{
|
|
std::string s = "abc";
|
|
assert((std::strcmp(s.c_str(), "abc")) == 0);
|
|
}
|
|
|
|
// # substring
|
|
{
|
|
std::string s = "abcde";
|
|
assert(s.substr(1, 3) == "bcd");
|
|
}
|
|
|
|
// # Split at a character into array of strings.
|
|
{
|
|
// Best stdlib solution for any character: http://stackoverflow.com/questions/236129/how-to-split-a-string-in-c
|
|
// There are shorters sstream solutions that split at whitespace.
|
|
// For Boost it's a one liner.
|
|
{
|
|
assert((split("01:23::45", ':') == std::vector<std::string>{"01", "23", "", "45"}));
|
|
|
|
std::vector<std::string> v;
|
|
split("01:23::45", ':', v);
|
|
assert((v == std::vector<std::string>{"01", "23", "", "45"}));
|
|
}
|
|
}
|
|
|
|
/*
|
|
# strip
|
|
|
|
# chomp
|
|
|
|
# trim
|
|
|
|
Exact same techniques as removing elements from vectors but for characters.
|
|
|
|
It's just that those operations are so common on strings...
|
|
|
|
http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring
|
|
*/
|
|
{
|
|
// A single character: remove and erase idiom.
|
|
// Single remove_all call in Boost.
|
|
{
|
|
std::string s = "a bc d";
|
|
auto end = s.end();
|
|
s.erase(std::remove(s.begin(), end, ' '), end);
|
|
assert((s == "abcd"));
|
|
}
|
|
|
|
// Any character in a string: remove_if + custom function. std::ispunct is a typical choice.
|
|
// Single liner with boost::remove_if + is_any_of.
|
|
{
|
|
std::string s = "a,bc. d";
|
|
auto end = s.end();
|
|
// stdc ispunct:
|
|
s.erase(std::remove_if(s.begin(), end, ::ispunct), end);
|
|
// stdlib ispunct. Fails without the cast.
|
|
//s.erase(std::remove_if(s.begin(), end, (int(*)(int))std::ispunct), end);
|
|
assert((s == "abc d"));
|
|
}
|
|
}
|
|
|
|
/*
|
|
# getline
|
|
|
|
Read istream until a any given character, by default newline, and store chars read into a string.
|
|
|
|
The other major method of getting data from streams is `operator<<`,
|
|
which generaly speaking reads until whitespace. getline is generaly saner.
|
|
|
|
Returns the stream itself, which allows to:
|
|
|
|
- chain calls
|
|
- do while(getline) combos, as streams can be converted to bool via the `void*()`
|
|
operator which returns a pointer type which is then converted to a boolean.
|
|
*/
|
|
{
|
|
// Up to newline.
|
|
{
|
|
std::stringstream ss;
|
|
std::string s;
|
|
ss << "ab\n\nc";
|
|
|
|
// The delim is removed from the string.
|
|
assert(std::getline(ss, s));
|
|
assert(s == "ab");
|
|
|
|
// Empty
|
|
assert(std::getline(ss, s));
|
|
assert(s == "");
|
|
|
|
// No problem if end of stream.
|
|
assert(std::getline(ss, s));
|
|
assert(s == "c");
|
|
|
|
// Stream over.
|
|
assert(!std::getline(ss, s));
|
|
}
|
|
|
|
// The stream itself is returned.
|
|
{
|
|
std::stringstream ss;
|
|
std::string s;
|
|
std::string s2;
|
|
ss << "ab\n\nc";
|
|
std::getline(std::getline(ss, s), s2);
|
|
assert(s == "ab");
|
|
assert(s2 == "");
|
|
}
|
|
|
|
// Up to custom char.
|
|
{
|
|
std::stringstream ss;
|
|
std::string s;
|
|
ss << "ab::f";
|
|
std::getline(ss, s, ':');
|
|
assert(s == "ab");
|
|
}
|
|
|
|
// Read stream line-wise.
|
|
{
|
|
std::stringstream ss;
|
|
std::string line;
|
|
std::vector<std::string> lines;
|
|
ss << "ab\n\nc";
|
|
while (getline(ss, line))
|
|
lines.push_back(line);
|
|
assert((lines == std::vector<std::string>{"ab", "", "c"}));
|
|
}
|
|
}
|
|
|
|
/*
|
|
# stringstream
|
|
|
|
# basic_stringstream
|
|
|
|
An iostream String backed implementation.
|
|
|
|
The following is defined:
|
|
|
|
typedef basic_stringstream<char> stringstream;
|
|
|
|
typedef basic_stringstream<char>
|
|
|
|
Very useful to test streams without creating files / stdin.
|
|
*/
|
|
{
|
|
std::stringstream oss("abcd");
|
|
|
|
// str does not clear the std::stringstream object
|
|
assert(oss.str() == "abcd");
|
|
|
|
// To clear it you could do: http://stackoverflow.com/questions/20731/in-c-how-do-you-clear-a-stringstream-variable
|
|
// Set to empty:
|
|
oss.str("");
|
|
// Clear flags. Very important, not only for error indicators but also for end of stream.
|
|
oss.clear();
|
|
assert(oss.str() == "");
|
|
|
|
// ERROR: use of deleted function because the constructor is =delete.
|
|
//oss = std::stringstream();
|
|
}
|
|
|
|
// Possible application: build up a huge string step by step.
|
|
// May be more efficient than concatenations which always generates new objects.
|
|
{
|
|
std::stringstream oss;
|
|
oss << "ab";
|
|
oss << "cd";
|
|
assert(oss.str() == "abcd");
|
|
}
|
|
|
|
/*
|
|
# int to string
|
|
|
|
There are a few standard alternatives.
|
|
|
|
<http://stackoverflow.com/questions/5590381/easiest-way-to-convert-int-to-string-in-c>
|
|
*/
|
|
{
|
|
/*
|
|
C++11 solves the question once and for all with a robust one-liner for base types.
|
|
|
|
It is not intended however for class input.
|
|
*/
|
|
#if __cplusplus >= 201103L
|
|
assert(std::to_string(123) == "123");
|
|
#endif
|
|
|
|
/*
|
|
std::stringstream seems to be the best pre C++11 solution.
|
|
|
|
It also has the advantage of working for any class that implements `operator<<`.
|
|
*/
|
|
{
|
|
std::stringstream oss;
|
|
oss << 123;
|
|
assert(oss.str() == "123");
|
|
}
|
|
|
|
/*
|
|
C sprintf
|
|
|
|
Works, but uses too many conversion operations.
|
|
*/
|
|
{
|
|
char cs[16];
|
|
std::sprintf(cs, "%d", 123);
|
|
std::string s = (cs);
|
|
assert(s == "123");
|
|
}
|
|
}
|
|
|
|
// #int to string
|
|
// http://stackoverflow.com/questions/7663709/convert-string-to-int-c
|
|
{
|
|
// Best C++11 error checking option: stoi
|
|
#if __cplusplus >= 201103L
|
|
assert(std::stoi("123") == 123);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*
|
|
# io
|
|
|
|
See cppref now: http://en.cppreference.com/w/cpp/io
|
|
|
|
Take a good look at the inheritance tree.
|
|
|
|
The following are defined:
|
|
|
|
extern istream cin; //standard input (stdin)
|
|
extern wistream wcin;
|
|
extern ostream cout; //standard output (stdout)
|
|
extern wostream wcout;
|
|
extern ostream cerr; //standard error (stderr)
|
|
extern wostream wcerr;
|
|
extern ostream clog; //standard log (stdlog)
|
|
extern wostream wclog;
|
|
|
|
# istream #ostream
|
|
|
|
Istream and ostream are IO interfaces.
|
|
|
|
They have many implementations, backed by different types of data:
|
|
|
|
- files
|
|
- strings in memory
|
|
|
|
The main methods of getting data out of streams are:
|
|
|
|
- getline for linewise operations
|
|
- operator << for word wise operations
|
|
- read(char*, size_t). Reads a fixed number of characters into an array.
|
|
|
|
# endl
|
|
|
|
System dependent newline.
|
|
|
|
*/
|
|
{
|
|
/*
|
|
# cout
|
|
|
|
stdout.
|
|
|
|
`ostream` object.
|
|
|
|
For tests, std::stringstream shall be used as the results can then be tested,
|
|
and the behaviour is identical to cout.
|
|
|
|
`<<` is very magic. You need to understand:
|
|
|
|
- operator overload
|
|
- function template argument deduction
|
|
- namespaces adl
|
|
|
|
before really understanding why it works.
|
|
|
|
# cerr
|
|
|
|
Cout for stderr
|
|
|
|
# clog
|
|
|
|
By default also points to stderr, but can be redirected with TODO.
|
|
*/
|
|
{
|
|
std::cout << "cout" << std::endl;
|
|
std::cerr << "cerr" << std::endl;
|
|
std::clog << "clog" << std::endl;
|
|
}
|
|
|
|
/*
|
|
# cin #stdin
|
|
|
|
`istream` object.
|
|
|
|
Avoid using it for similar reasons as scanf:
|
|
|
|
- hard to handle invalid inputs
|
|
- difficult to predict behaviour
|
|
|
|
getline is the best option.
|
|
*/
|
|
{
|
|
//std::cout << "Enter an integer:" << endl;
|
|
//std::cin >> i;
|
|
//std::cout << i << std::endl;
|
|
}
|
|
|
|
// This is how a very explicit usage of `<<` would look like
|
|
{
|
|
std::stringstream ss;
|
|
|
|
//TODO0 how to get his working?
|
|
//std::operator<<<std::ostream,std::string>(ss, "explicit");
|
|
|
|
std::operator<<(std::operator<<(ss, "explicit "), "call");
|
|
}
|
|
|
|
// #<< left shift overload
|
|
{
|
|
}
|
|
|
|
// #>> right shift overload istream
|
|
// Get input out of streams into string.
|
|
// Overloaded for many different types of inputs: <http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/>
|
|
{
|
|
// char*, std::string
|
|
// - skip whitespace as defined by `isspace`.
|
|
// - read until first whitespace found
|
|
{
|
|
std::stringstream ss("ab cd\tef \t\ngh i.;)j");
|
|
std::string s;
|
|
ss >> s;
|
|
assert(s == "ab");
|
|
ss >> s;
|
|
assert(s == "cd");
|
|
ss >> s;
|
|
assert(s == "ef");
|
|
ss >> s;
|
|
assert(s == "gh");
|
|
ss >> s;
|
|
assert(s == "i.;)j");
|
|
}
|
|
|
|
// Numeric types: int, float.
|
|
// - skip whitespace as defined by `isspace`.
|
|
// - read until cannot be part of the type anymore (TODO what does that mean exactly?)
|
|
{
|
|
std::stringstream ss("1.0 2 \n \t 3.0f 4a a");
|
|
float f;
|
|
std::string s;
|
|
ss >> f;
|
|
assert(f == 1.0f);
|
|
ss >> f;
|
|
assert(f == 2.0f);
|
|
ss >> f;
|
|
assert(f == 3.0f);
|
|
|
|
// f suffix is not part of floats
|
|
ss >> s;
|
|
assert(s == "f");
|
|
|
|
ss >> f;
|
|
// TODO what happens? Error checking.
|
|
}
|
|
|
|
// Since `>>` returns the istream, it is possible to chain calls:
|
|
{
|
|
std::stringstream ss("1 1.5 2");
|
|
int i, j;
|
|
float f;
|
|
ss >> i >> f >> j;
|
|
assert(i == 1);
|
|
assert(f == 1.5);
|
|
assert(j == 2);
|
|
}
|
|
}
|
|
|
|
/*
|
|
# printf format strings
|
|
|
|
In C++ there is no more printf formatting strings: must use the C libs for that.
|
|
|
|
It is possible however to obtain some level of formatting control with manipulators.
|
|
|
|
# manipulators
|
|
|
|
Allow to control the output format.
|
|
*/
|
|
{
|
|
/*
|
|
# boolalpha
|
|
|
|
Control the format of boolean printing.
|
|
|
|
- on: print `true` or `false`
|
|
- no: print `1` or `0` (default)
|
|
|
|
Mnemonic: if true use alpha chars. Else, use numeric chars.
|
|
*/
|
|
{
|
|
std::stringstream ss;
|
|
|
|
ss << std::boolalpha << true;
|
|
assert(ss.str() == "true");
|
|
ss.str("");
|
|
|
|
ss << std::noboolalpha << true;
|
|
assert(ss.str() == "1");
|
|
ss.str("");
|
|
|
|
//default is noboolalpha
|
|
ss << true;
|
|
assert(ss.str() == "1");
|
|
ss.str("");
|
|
}
|
|
|
|
/*
|
|
Once an options is eaten by the ostream, it stays as the default option.
|
|
*/
|
|
{
|
|
std::stringstream ss;
|
|
|
|
ss << std::boolalpha;
|
|
|
|
ss << true;
|
|
assert(ss.str() == "true");
|
|
ss.str("");
|
|
//does not clear earlier passed options
|
|
|
|
ss << true;
|
|
assert(ss.str() == "true");
|
|
ss.str("");
|
|
|
|
ss << std::noboolalpha;
|
|
|
|
ss << true;
|
|
assert(ss.str() == "1");
|
|
ss.str("");
|
|
}
|
|
|
|
/*
|
|
# width
|
|
|
|
Minimum number of chars to output.
|
|
|
|
If not enough, complete with fill.
|
|
|
|
# fill
|
|
|
|
See width.
|
|
|
|
# left right internal
|
|
*/
|
|
{
|
|
std::stringstream ss;
|
|
int i = 12;
|
|
|
|
ss.width(4);
|
|
ss.fill(' ');
|
|
|
|
ss << std::left << i;
|
|
assert(ss.str() == "12 ");
|
|
ss.str("");
|
|
|
|
ss << std::right << i;
|
|
//assert(ss.str() == " 12");
|
|
//why fails?
|
|
ss.str("");
|
|
}
|
|
|
|
/*
|
|
# dec #hex #oct
|
|
|
|
Control how integers are printed.
|
|
*/
|
|
{
|
|
std::stringstream ss;
|
|
|
|
ss << std::hex << 10;
|
|
assert(ss.str() == "a");
|
|
ss.str("");
|
|
|
|
ss << std::oct << 10;
|
|
assert(ss.str() == "12");
|
|
ss.str("");
|
|
|
|
ss << std::dec << 10;
|
|
assert(ss.str() == "10");
|
|
ss.str("");
|
|
|
|
ss << 10;
|
|
assert(ss.str() == "10");
|
|
ss.str("");
|
|
}
|
|
|
|
/*
|
|
# scientific fixed none
|
|
|
|
# precision
|
|
|
|
Controls number of digits to print.
|
|
*/
|
|
{
|
|
std::stringstream ss;
|
|
ss.precision(3);
|
|
float f = 1.2345;
|
|
|
|
//none is the default
|
|
ss << f;
|
|
assert(ss.str() == "1.23");
|
|
ss.str("");
|
|
|
|
ss << std::fixed << f;
|
|
assert(ss.str() == "1.235");
|
|
ss.str("");
|
|
|
|
ss << std::scientific << f;
|
|
assert(ss.str() == "1.235e+00");
|
|
ss.str("");
|
|
|
|
/*
|
|
None can only be set via `unsetf(ios_base::floatfield)`.
|
|
*/
|
|
{
|
|
ss.unsetf(std::ios_base::floatfield);
|
|
ss << f;
|
|
assert(ss.str() == "1.23");
|
|
ss.str("");
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
# file io
|
|
|
|
# ifstream
|
|
|
|
# ofstream
|
|
|
|
# fstream
|
|
*/
|
|
{
|
|
std::string path("fileio.tmp");
|
|
std::string data("ab\n\nc\n");
|
|
|
|
// Write to file.
|
|
{
|
|
std::ofstream ofs(path);
|
|
if (ofs) {
|
|
ofs << data;
|
|
ofs.close();
|
|
} else {
|
|
ios_write_fail(path);
|
|
}
|
|
}
|
|
|
|
// #Read entire file at once: stackoverflow.com/questions/2602013/read-whole-ascii-file-into-c-stdstring
|
|
// Best way seems to be to get file size, allocate, and read manually.
|
|
{
|
|
std::ifstream ifs(path);
|
|
if (ifs) {
|
|
std::string data_read;
|
|
read_file(ifs, data_read);
|
|
assert(data_read == data);
|
|
} else {
|
|
ios_read_fail(path);
|
|
}
|
|
}
|
|
|
|
// #Copy file to another. #cp
|
|
// #rdbuf http://stackoverflow.com/questions/2141749/what-does-ifstreamrdbuf-actually-do
|
|
{
|
|
std::string data = "abc\ndef\n";
|
|
std::string src_path = "src.tmp";
|
|
std::string dst_path = "dst.tmp";
|
|
// Create input file.
|
|
{
|
|
std::ofstream src(src_path, std::ios::binary);
|
|
src << data;
|
|
// 2 times 4 Gb.
|
|
//for (int i = 0; i < 2; i++) {
|
|
//for (int j = 0; j < 0xFFFFFFFF; j++) {
|
|
//src << std::hex << j;
|
|
//}
|
|
//}
|
|
src.close();
|
|
}
|
|
// Copy.
|
|
std::ifstream src(src_path, std::ios::binary);
|
|
std::ofstream dst(dst_path, std::ios::binary);
|
|
dst << src.rdbuf();
|
|
src.close();
|
|
dst.close();
|
|
// Check copy.
|
|
{
|
|
std::ifstream dst(dst_path, std::ios::binary);
|
|
std::string data_read;
|
|
read_file(dst, data_read);
|
|
assert(data_read == data);
|
|
src.close();
|
|
}
|
|
}
|
|
|
|
// #Compare two files larger than memory.
|
|
// TODO is there an easier way than reading each?
|
|
{
|
|
}
|
|
|
|
// #Append to file.
|
|
{
|
|
std::ofstream ofs(path);
|
|
|
|
if (ofs) {
|
|
ofs << data;
|
|
ofs.close();
|
|
} else {
|
|
ios_write_fail(path);
|
|
}
|
|
|
|
// #open #Reopen
|
|
// Can be used to reopen ofstream with new properties.
|
|
// Also consider clearing error flags if there can be any.
|
|
//ofs.clear()
|
|
ofs.open(path, std::ios::app);
|
|
if (ofs) {
|
|
ofs << data;
|
|
ofs.close();
|
|
} else {
|
|
ios_write_fail(path);
|
|
}
|
|
|
|
std::ifstream ifs(path);
|
|
if (ifs) {
|
|
std::string data_read;
|
|
read_file(ifs, data_read);
|
|
assert(data_read == data + data);
|
|
} else {
|
|
ios_read_fail(path);
|
|
}
|
|
}
|
|
|
|
/*
|
|
# binary io
|
|
|
|
Use ios::binary, and the binary functions write and read.
|
|
*/
|
|
{
|
|
// TODO
|
|
//std::string path("binary.tmp");
|
|
//std::vector<int> data{0x123, 0x456};
|
|
//std::vector<int>::size_type size = data.size();
|
|
//std::vector<int> data_read(size);
|
|
//std::ofstream ofs(path, std::ios::binary);
|
|
//if (ofs) {
|
|
//ofs.write(&data[0], size);
|
|
//ofs.close();
|
|
//} else {
|
|
//ios_write_fail(path);
|
|
//}
|
|
|
|
//std::ifstream ifs(path);
|
|
//if (ifs) {
|
|
//std::string data_read;
|
|
//read_file(ifs, data_read);
|
|
//assert(data_read == data);
|
|
//} else {
|
|
//ios_read_fail(path);
|
|
//}
|
|
}
|
|
|
|
/*
|
|
# error handling
|
|
|
|
# is_open vs bool cast
|
|
|
|
`is_open` false implies `operator bool()` false, but the converse is false: `operator bool()` is more strict.
|
|
|
|
<http://stackoverflow.com/questions/14920457/c-difference-between-casting-ifstream-to-bool-and-using-ifstreamis-open>
|
|
|
|
IO functions do not raise exceptions by default, but may be turned on.
|
|
|
|
The best standard exception to raise is probably `std::ios_base::failure`.
|
|
|
|
Relevant standard exceptions:
|
|
|
|
http://en.cppreference.com/w/cpp/io/ios_base/failure
|
|
|
|
SO thread:
|
|
|
|
http://stackoverflow.com/questions/9670396/exception-handling-and-opening-a-file
|
|
*/
|
|
{
|
|
std::string path("i_dont_exist.tmp");
|
|
std::ifstream ifs(path);
|
|
if (ifs) {
|
|
} else {
|
|
try {
|
|
throw std::ios_base::failure("Error: Could not write to file: " + path);
|
|
} catch (std::ios_base::failure e) {
|
|
std::clog << e.what() << std::endl;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// # ios::in: flag automatically set for ifstream, but not fstream
|
|
//http://stackoverflow.com/questions/7463410/is-iosin-needed-for-ifstreams-opened-in-binary-mode
|
|
}
|
|
}
|
|
|
|
/*
|
|
# path #directory #join
|
|
|
|
Like in C, no system independant path or directory operations (for the love of God...)
|
|
|
|
Boost does have a system independant path separator.
|
|
|
|
Some Boost fs features were proposed on TR2.
|
|
*/
|
|
|
|
#if __cplusplus >= 201103L
|
|
/*
|
|
# static_assert
|
|
|
|
Make assertions at compile time.
|
|
|
|
In this way you don't waste time compiling large programs,
|
|
or do potentially dangerous runtime operations to test your program.
|
|
|
|
Probably became possible on C++11 because of features such as `constexpr`,
|
|
which allow to better manage compile time constantness.
|
|
|
|
<http://stackoverflow.com/questions/1647895/what-does-static-assert-do-and-what-would-you-use-it-for>
|
|
*/
|
|
{
|
|
static_assert(0 < 1, "msg");
|
|
|
|
// ERROR: static assertion failed
|
|
//static_assert(0 > 1, "msg");
|
|
|
|
std::srand(time(NULL));
|
|
// ERROR: needs to be a constexpr
|
|
//static_assert(std::rand() >= 0);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
# limits
|
|
|
|
C++ version of climits.
|
|
|
|
Contains information on the built-in types, inclding largest and smallest of each type.
|
|
|
|
TODO compare to climits which uses macros. Advantage of templates is the scoping?
|
|
*/
|
|
{
|
|
std::cout << "numeric_limits<int>::" << std::endl;
|
|
std::cout << " max() = " << std::numeric_limits<int>::max() << std::endl;
|
|
std::cout << " min() = " << std::numeric_limits<int>::min() << std::endl;
|
|
std::cout << " digits = " << std::numeric_limits<int>::digits << std::endl;
|
|
std::cout << " is_signed = " << std::numeric_limits<int>::is_signed << std::endl;
|
|
std::cout << " is_integer = " << std::numeric_limits<int>::is_integer << std::endl;
|
|
std::cout << std::endl;
|
|
}
|
|
|
|
/*
|
|
# utility
|
|
|
|
Lots of miscelaneous utilities.
|
|
|
|
<http://en.cppreference.com/w/cpp/utility>
|
|
*/
|
|
{
|
|
|
|
#if __cplusplus >= 201103L
|
|
/*
|
|
# tuple
|
|
|
|
Hold a ordered collection of elements.
|
|
|
|
Each element can be of a different type.
|
|
|
|
The length is always fixed.
|
|
*/
|
|
{
|
|
//create
|
|
{
|
|
//constructor
|
|
{
|
|
std::tuple<int,char,std::string> t0(0, 'a', "a");
|
|
}
|
|
|
|
/*
|
|
# make_tuple
|
|
|
|
forwards arguments to tuple constructor.
|
|
|
|
The advantage over the constructor is that since it is a function
|
|
template argument deduction can be done, so we don't need to type in
|
|
template arguments.
|
|
|
|
Remember that template argument deduction cannot be done for constructors.
|
|
*/
|
|
{
|
|
std::tuple<int,char,std::string> t;
|
|
|
|
//without make_tuple
|
|
t = std::make_tuple(0, 'a', "a");
|
|
t = std::tuple<int,char,std::string>(0, 'a', "a");
|
|
|
|
//with make_tuple
|
|
}
|
|
|
|
//tuple from pair
|
|
{
|
|
std::tuple<int,char> t2( std::pair<int,char>(0, 'a'));
|
|
}
|
|
|
|
//uniform initialization
|
|
{
|
|
std::tuple<int,char,std::string> t{0, 'a', "a"};
|
|
}
|
|
|
|
// Fails because the tuple constructor are is `explicit`!
|
|
// TODO Rationale? <http://stackoverflow.com/questions/14961809/returning-a-tuple-from-a-function-using-uniform-initialization-syntax>
|
|
{
|
|
//std::tuple<int, int> t = {0, 1};
|
|
//std::tuple<int, int> t[]{{0, 1}};
|
|
}
|
|
}
|
|
|
|
/*
|
|
# get
|
|
|
|
Get single element from tuple.
|
|
|
|
Returns references, so it is possible to modify the tuples with them.
|
|
|
|
Copies are made from input elements
|
|
*/
|
|
{
|
|
std::tuple<int,std::string> t0(0, "abc");
|
|
|
|
assert(std::get<0>(t0) == 0);
|
|
assert(std::get<1>(t0) == "abc");
|
|
|
|
std::get<0>(t0) = 1;
|
|
assert(std::get<0>(t0) == 1);
|
|
|
|
std::get<1>(t0)[0] = '0';
|
|
assert(std::get<1>(t0) == "0bc");
|
|
}
|
|
|
|
/*
|
|
# tie
|
|
|
|
Unpack a tuple.
|
|
|
|
Unpack by reference seems not to be possible: <http://stackoverflow.com/questions/16571883/unpacking-a-std-tuple-into-pointers>
|
|
|
|
# ignore
|
|
|
|
Magic that exists only to ignore one of tie outputs.
|
|
*/
|
|
{
|
|
int i;
|
|
std::string s;
|
|
std::tuple<int,float,std::string> t(1, 1.5, "abc");
|
|
std::tie(i, std::ignore, s) = t;
|
|
assert(i == 1);
|
|
assert(s == "abc");
|
|
|
|
// Clearly copies are made.
|
|
i = 2;
|
|
assert(std::get<0>(t) == 1);
|
|
}
|
|
|
|
/*
|
|
Relational operators operations are implemented
|
|
|
|
<http://www.cplusplus.com/reference/tuple/tuple/operators/>
|
|
|
|
`<` family is lexicographical.
|
|
*/
|
|
{
|
|
std::tuple<int,char> t0(0, 'a');
|
|
std::tuple<int,char> t1(0, 'a');
|
|
std::tuple<int,char> t2(1, 'b');
|
|
std::tuple<int,char> t3(-1, 'b');
|
|
std::tuple<int,char> t4(0, 'b');
|
|
|
|
assert(t0 == t1);
|
|
assert(t0 != t2);
|
|
assert(t0 < t2);
|
|
assert(t0 > t3); //-1 counts
|
|
assert(t0 < t4); //0 ties, 'a' < 'b'
|
|
}
|
|
|
|
//swap contents of two tuples of same type
|
|
{
|
|
std::tuple<int,char> t0(0, 'a');
|
|
std::tuple<int,char> t1(1, 'b');
|
|
|
|
std::tuple<int,char> old_t0 = t0;
|
|
std::tuple<int,char> old_t1 = t1;
|
|
|
|
t0.swap(t1);
|
|
|
|
assert(t0 == old_t1);
|
|
assert(t1 == old_t0);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
# pair
|
|
|
|
Particular case of tuple for two elements
|
|
|
|
Methods which also exist for tuple will not be discussed.
|
|
|
|
Specially important because of `map`.
|
|
*/
|
|
{
|
|
//access: can also be done via `.first` and `.second` in addition to tuple `get`.
|
|
{
|
|
std::pair<int,char> p(0, 'a');
|
|
assert(std::get<0>(p) == p.first);
|
|
assert(std::get<1>(p) == p.second);
|
|
}
|
|
}
|
|
|
|
/*
|
|
# forward
|
|
|
|
TODO
|
|
*/
|
|
{
|
|
}
|
|
}
|
|
|
|
/*
|
|
# containers
|
|
|
|
The stdlib furnishes several containers.
|
|
|
|
It is a very important part of an algorithm to choose the right container for the task.
|
|
|
|
As of C++11, most containers are abstract, that is, only specify which operations it supports.
|
|
|
|
For example, a `UnorderedMap` could be implemented both as a hash map or a RB tree concrete data structures,
|
|
but is always supports the same operations: insert, remove, and so on.
|
|
|
|
The major data structures which you must know about in order of decreasing usefulness are:
|
|
|
|
- std::vector
|
|
- set
|
|
- map
|
|
- list
|
|
- deque
|
|
- heap and priority queue
|
|
*/
|
|
|
|
/*
|
|
# vector
|
|
|
|
Array backed conatiner that grows / shrinks as necessary.
|
|
|
|
$O(1)$ random access.
|
|
|
|
$O(n)$ element removal from interior
|
|
|
|
$O(1)$ element append to end (amortized, $O(n)$ worst case)
|
|
|
|
All methods that work for several SLT containers shall only be cheated here once.
|
|
*/
|
|
{
|
|
// Create
|
|
{
|
|
// Empty
|
|
{
|
|
std::vector<int> v;
|
|
// C++11 initializer lists:
|
|
std::vector<int> v1{};
|
|
assert(v == v1);
|
|
}
|
|
|
|
/*
|
|
Fill constructor.
|
|
|
|
Make a `std::vector` with n copies of a single value.
|
|
*/
|
|
{
|
|
//copies of given object
|
|
{
|
|
assert(std::vector<int>(3, 2) == std::vector<int>({2, 2, 2}));
|
|
}
|
|
|
|
//default constructed objects. int = 0.
|
|
{
|
|
assert(std::vector<int>(3) == std::vector<int>({0, 0, 0}));
|
|
}
|
|
}
|
|
|
|
// Range copy.
|
|
{
|
|
std::vector<int> v{0, 1, 2};
|
|
std::vector<int> v1(v.begin(), v.end());
|
|
assert(v == v1);
|
|
}
|
|
|
|
// From existing array.
|
|
{
|
|
int myints[]{0, 1, 2};
|
|
std::vector<int> v(myints, myints + sizeof(myints) / sizeof(int));
|
|
std::vector<int> v1 = {0, 1, 2};
|
|
assert(v == v1);
|
|
}
|
|
}
|
|
|
|
// Vectors have order.
|
|
{
|
|
std::vector<int> v{0, 1, 2};
|
|
std::vector<int> v1{2, 1, 0};
|
|
assert(v != v1);
|
|
}
|
|
|
|
/*
|
|
# Contigous storage
|
|
|
|
# Data
|
|
|
|
Storage is required to be contiguous by TR1:
|
|
http://stackoverflow.com/questions/849168/are-stdvector-elements-guaranteed-to-be-contiguous
|
|
|
|
C++11 introduces the `data()` method which returns a pointer to the first element.
|
|
It works even if the vector is empty.
|
|
http://stackoverflow.com/questions/6485496/how-to-get-stdvector-pointer-to-the-raw-data
|
|
|
|
Before C++11, `&v[0]` works for non-empty vectors.
|
|
|
|
`vector<bool>` as usual is an exception.
|
|
*/
|
|
{
|
|
std::vector<int> v{0, 1, 2};
|
|
assert(&v[0] == v.data());
|
|
// True because contiguous:
|
|
assert(v.data()[1] == v[1]);
|
|
}
|
|
|
|
// size methods
|
|
{
|
|
/*
|
|
# size
|
|
|
|
# length of vector
|
|
|
|
# size_type
|
|
|
|
Number of elements in std::vector.
|
|
|
|
This has type std::vector<X>::size_type
|
|
*/
|
|
{
|
|
std::vector<int> v;
|
|
assert(v.size() == 0);
|
|
v.push_back(0);
|
|
assert(v.size() == 1);
|
|
}
|
|
|
|
/*
|
|
# resize
|
|
|
|
If larger than current size, append given element at end.
|
|
|
|
If smaller than current size, remove elements from end.
|
|
*/
|
|
{
|
|
// Reduce size
|
|
{
|
|
std::vector<int> v{0, 1};
|
|
v.resize(1);
|
|
assert((v == std::vector<int>{0}));
|
|
}
|
|
|
|
// Increase size
|
|
{
|
|
|
|
// Using default constructor objects.
|
|
{
|
|
std::vector<int> v{1};
|
|
v.resize(3);
|
|
assert((v == std::vector<int>{1, 0, 0}));
|
|
}
|
|
|
|
// Using copies of given object.
|
|
{
|
|
std::vector<int> v{1};
|
|
v.resize(3, 2);
|
|
assert((v == std::vector<int>{1, 2, 2}));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Capacity methods.
|
|
{
|
|
/*
|
|
# capacity
|
|
|
|
Get currently allocated size.
|
|
|
|
Different from size, which is the number of elements in the std::vector!
|
|
|
|
At least as large as size.
|
|
|
|
Likely to be a power of 2 on most implementations.
|
|
*/
|
|
{
|
|
std::vector<int> v;
|
|
v.push_back(0);
|
|
v.push_back(1);
|
|
v.push_back(2);
|
|
assert(v.capacity() >= 3);
|
|
std::cout << "capacity = " << v.capacity() << std::endl;
|
|
}
|
|
|
|
// # max_size: estimative of what your OS allows you to allocate
|
|
{
|
|
std::cout << "max_size (MiB) = " << std::vector<int>().max_size() / (1 << 20) << std::endl;
|
|
}
|
|
|
|
// # reserve: increase allocated size if larger than current size.
|
|
{
|
|
std::vector<int> v;
|
|
v.reserve(3);
|
|
assert(v.capacity() >= 3);
|
|
// size() is untouched
|
|
assert(v.empty());
|
|
}
|
|
|
|
#if __cplusplus >= 201103L
|
|
// # shrink_to_fit
|
|
{
|
|
std::vector<int> v{0, 1};
|
|
v.reserve(4);
|
|
v.shrink_to_fit();
|
|
assert(v.capacity() == 2);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// `std::vector` stores copies of elements, not references.
|
|
{
|
|
std::string s = "abc";
|
|
std::vector<std::string> v{s};
|
|
v[0][0] = '0';
|
|
assert(v[0] == "0bc");
|
|
assert(s == "abc");
|
|
}
|
|
|
|
// Modify.
|
|
{
|
|
{
|
|
std::vector<int> v;
|
|
v = {0};
|
|
v = {0, 1};
|
|
assert((v == std::vector<int>{0, 1}));
|
|
}
|
|
|
|
/*
|
|
# push_back
|
|
|
|
# append
|
|
|
|
Push to the end of the std::vector.
|
|
|
|
Amortized time O(1), but may ocassionaly make the std::vector grow,
|
|
which may required a full data copy to a new location if the
|
|
current backing array cannot grow.
|
|
|
|
# push_front
|
|
|
|
Does not exist for std::vector, as it would always be too costly (requires to move
|
|
each element forward.) Use deque if you need that.
|
|
*/
|
|
{
|
|
std::vector<int> v;
|
|
std::vector<int> v1;
|
|
|
|
v.push_back(0);
|
|
v1 = {0};
|
|
assert(v == v1);
|
|
|
|
v.push_back(1);
|
|
v1 = {0, 1};
|
|
assert(v == v1);
|
|
|
|
/*
|
|
push_back makes copies with assign `=`
|
|
|
|
If you want references, use pointers, or even better, auto_ptr.
|
|
*/
|
|
{
|
|
std::vector<std::string> v;
|
|
std::string s = "abc";
|
|
|
|
v.push_back(s);
|
|
v[0][0] = '0';
|
|
assert(v[0] == "0bc");
|
|
|
|
//s was not changed
|
|
assert(s == "abc");
|
|
}
|
|
}
|
|
|
|
/*
|
|
# pop_back
|
|
|
|
Remove last element from std::vector.
|
|
|
|
No return val. Rationale: <http://stackoverflow.com/questions/12600330/pop-back-return-value>
|
|
*/
|
|
{
|
|
std::vector<int> v{0, 1};
|
|
|
|
v.pop_back();
|
|
assert(v == std::vector<int>{0});
|
|
|
|
v.pop_back();
|
|
assert(v == std::vector<int>{});
|
|
}
|
|
|
|
/*
|
|
# insert
|
|
|
|
This operation is inneficient for `std::vector` if it is not done at the end.
|
|
|
|
# concatenate
|
|
|
|
The range form of insert can be used to append one vector to anoter.
|
|
*/
|
|
{
|
|
// Single element form.
|
|
{
|
|
std::vector<int> v = {0,1};
|
|
std::vector<int> v1;
|
|
|
|
v.insert(v.begin(), -1);
|
|
v1 = {-1, 0, 1};
|
|
assert(v == v1);
|
|
|
|
v.insert(v.end(), 2);
|
|
v1 = {-1, 0, 1, 2};
|
|
assert(v == v1);
|
|
}
|
|
|
|
// Range form.
|
|
{
|
|
std::vector<int> v = {0,1};
|
|
std::vector<int> v1 = {2,3};
|
|
|
|
v.insert(v.end(), v1.begin(), v1.end());
|
|
assert((v == std::vector<int>{0, 1, 2, 3}));
|
|
}
|
|
}
|
|
|
|
/*
|
|
# erase
|
|
|
|
Remove given elements from container given iterators to those elements.
|
|
|
|
This operation is inneficient for std::vectors,
|
|
since it may mean reallocation and therefore up to $O(n)$ operations.
|
|
|
|
Returns a pointer to the new location of the element next to the last removed element.
|
|
*/
|
|
{
|
|
// Single element
|
|
{
|
|
std::vector<int> v{0, 1, 2};
|
|
auto it = v.erase(v.begin() + 1);
|
|
assert((v == std::vector<int>{0, 2}));
|
|
assert(*it == 2);
|
|
}
|
|
|
|
// Range
|
|
{
|
|
std::vector<int> v{0, 1, 2, 3};
|
|
auto it = v.erase(v.begin() + 1, v.end() - 1);
|
|
assert((v == std::vector<int>{0, 3}));
|
|
assert(*it == 3);
|
|
}
|
|
}
|
|
|
|
/*
|
|
# remove
|
|
|
|
Helper to remove all elements that compare equal to a value from container.
|
|
|
|
Does not actually remove the elements: only ensures that the beginning of the range
|
|
does not contain the item to be removed.
|
|
|
|
Ex:
|
|
|
|
0, 1, 0, 2, 0, 1
|
|
|
|
Value to remove: `0`
|
|
|
|
Range to remove from:
|
|
|
|
0, 1, 0, 2, 0, 1
|
|
----------
|
|
|
|
After the remove:
|
|
|
|
1, 2, X, Y, 0, 1
|
|
----------
|
|
|
|
where `X` and `Y` are trash, and not necessarily 0!
|
|
|
|
To actually remove the items, an `erase` is needed after remove
|
|
because `remove` is not a class method and thus cannot remove items from a container.
|
|
|
|
This is called the erase and remove idiom.
|
|
|
|
After a remove the container becomes:
|
|
|
|
1, 2, 0, 1
|
|
|
|
# erase and remove idiom
|
|
|
|
# remove and erase idiom
|
|
|
|
See remove.
|
|
*/
|
|
{
|
|
// Verbose version
|
|
{
|
|
std::vector<int> v{0, 1, 0, 2, 0, 1};
|
|
auto end = std::next(v.end(), -2);
|
|
auto firstTrashIt = std::remove(v.begin(), end, 0);
|
|
// Unpredictable result:
|
|
std::cout << "remove:";
|
|
for (auto& i : v) std::cout << " " << i;
|
|
std::cout << std::endl;
|
|
v.erase(firstTrashIt, end);
|
|
assert((v == std::vector<int>{1, 2, 0, 1}));
|
|
}
|
|
|
|
// Compact version
|
|
{
|
|
std::vector<int> v{0, 1, 0, 2, 0, 1};
|
|
auto end = std::next(v.end(), -2);
|
|
v.erase(std::remove(v.begin(), end, 0), end);
|
|
assert((v == std::vector<int>{1, 2, 0, 1}));
|
|
}
|
|
}
|
|
|
|
// # remove_if # filter
|
|
// Algorithm. Remove if a given function evaluates to true on an element.
|
|
{
|
|
std::vector<int> v{0, 1, 2, 3, 4};
|
|
auto end = v.end();
|
|
v.erase(std::remove_if(v.begin(), end, odd), end);
|
|
assert((v == std::vector<int>{0, 2, 4}));
|
|
|
|
// Common combo with lambdas
|
|
{
|
|
std::vector<int> v{0, 1, 2, 3, 4};
|
|
auto end = v.end();
|
|
v.erase(std::remove_if(v.begin(), end,
|
|
[](int i) {return i % 2 == 1;}), end);
|
|
assert((v == std::vector<int>{0, 2, 4}));
|
|
}
|
|
}
|
|
|
|
// # transform
|
|
// Algorithm. Replace elements by output of a function.
|
|
{
|
|
std::vector<int> v{0, 1, 2};
|
|
std::transform(v.begin(), v.end(), v.begin(),
|
|
[](int i) {return i * i;});
|
|
assert((v == std::vector<int>{0, 1, 4}));
|
|
}
|
|
|
|
// # clear
|
|
{
|
|
std::vector<int> v{0, 1, 2};
|
|
v.clear();
|
|
assert(v.size() == 0);
|
|
}
|
|
|
|
/*
|
|
# print vector
|
|
|
|
# vector to string
|
|
|
|
No built-in way.
|
|
|
|
http://stackoverflow.com/questions/4850473/pretty-print-c-stl-containers
|
|
190 votes on question, 30 on top answer! Come on C++!
|
|
|
|
http://stackoverflow.com/questions/1430757/c-vector-to-string?lq=1
|
|
*/
|
|
// ERROR: no default operator `<<`.
|
|
//cout << v;
|
|
}
|
|
|
|
// Random access is O(1) since array backed
|
|
{
|
|
|
|
std::vector<int> v{0, 1, 2};
|
|
|
|
// First element:
|
|
|
|
assert(v.front() == 0);
|
|
assert(v.front() == v[0]);
|
|
|
|
// Last element:
|
|
|
|
assert(v.back() == 2);
|
|
|
|
// Nth element:
|
|
|
|
v[0] = 1;
|
|
assert(v[0] == 1);
|
|
|
|
/*
|
|
BAD: just like array overflow will not change std::vector size,
|
|
and is unlikelly to give an error
|
|
*/
|
|
{
|
|
//v1[2] = 2;
|
|
}
|
|
|
|
// #back Get reference to last element in vector.
|
|
// #front Get reference to first element in vector.
|
|
// #at Like `[]`, but does bound checking and throws `out_of_range` in case of overflow.
|
|
{
|
|
std::vector<int> v{0, 1, 2};
|
|
assert(v.front() == 0);
|
|
assert(v.at(1) == 1);
|
|
assert(v.back() == 2);
|
|
try {
|
|
assert(v.at(3) == 0);
|
|
} catch (std::out_of_range& e) {
|
|
} catch (...) {
|
|
assert(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
# bool std::vector
|
|
|
|
*bool std::vectors are evil!*
|
|
|
|
The standard requires `vector` to have an specialization for bool which packs bits efficiently.
|
|
|
|
While efficient, in order to work this specialization breaks common std::vector interfaces
|
|
that require taking addresses only in the case of this specialization, since it does not
|
|
make sense to takes addresses anymore.
|
|
|
|
Alternatives to `vector<bool>`: <http://stackoverflow.com/questions/670308/alternative-to-vectorbool>
|
|
|
|
A good alternative seem to be deque<bool>, which behaves as intended.
|
|
*/
|
|
{
|
|
// Works fine and dandy as expected.
|
|
{
|
|
std::vector<int> v{1, 0};
|
|
int& i(v[0]);
|
|
}
|
|
|
|
// Does not compile!!!
|
|
{
|
|
std::vector<bool> v{true, false};
|
|
//bool& b(v[0]);
|
|
}
|
|
|
|
// It was not a problem with bool, the problem really is `vector<bool>`.
|
|
{
|
|
bool b[]{true, false};
|
|
bool& b2(b[0]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
# deque
|
|
|
|
Double ended queue.
|
|
|
|
Random access.
|
|
|
|
Very similar interface to std::vector, except that:
|
|
|
|
- insertion to front is O(1)
|
|
- there is no guarantee of inner storage contiguity
|
|
|
|
Discussion on when to use deque or std::vector:
|
|
<http://stackoverflow.com/questions/5345152/why-would-i-prefer-using-vector-to-deque>
|
|
|
|
It is controversial if one should use deque or std::vector as the main generic container.
|
|
*/
|
|
|
|
/*
|
|
# set
|
|
|
|
- unique elements: inserting twice does nothing
|
|
|
|
- always ordered: $O(log)$ find / insert
|
|
|
|
- immutable elements: it is not possible to modify an object,
|
|
one must first remove it and resinsert.
|
|
|
|
This is so because modification may mean reordering.
|
|
*/
|
|
{
|
|
// C++11 initializer list
|
|
{
|
|
{
|
|
std::set<int> s{1, 2, 0, 1};
|
|
std::set<int> s2{0, 1, 2};
|
|
assert(s == s2);
|
|
}
|
|
|
|
{
|
|
std::set<std::string> s = {"a", "c", "b", "a"};
|
|
std::set<std::string> s1 = {"a","b", "c"};
|
|
assert(s == s1);
|
|
}
|
|
}
|
|
|
|
// You can modify objects if you store pointers.
|
|
{
|
|
int i = 0;
|
|
std::set<int*> s;
|
|
s.insert(&i);
|
|
std::set<int*>::iterator it = s.find(&i);
|
|
*(*it) = 1;
|
|
assert(i == 1);
|
|
}
|
|
|
|
/*
|
|
# insert
|
|
|
|
Like for std::vector, insert makes copies.
|
|
|
|
Return is a pair conatining:
|
|
|
|
- if the item was not present, an iterator to the item inserted and true
|
|
- if the item was present, an iterator to the existing item inserted and false
|
|
*/
|
|
{
|
|
std::pair<std::set<int,std::string>::iterator,bool> ret;
|
|
std::set<int> s;
|
|
|
|
ret = s.insert(1);
|
|
assert(ret.first == s.find(1));
|
|
assert(ret.second == true);
|
|
|
|
ret = s.insert(2);
|
|
assert(ret.first == s.find(2));
|
|
assert(ret.second == true);
|
|
|
|
ret = s.insert(0);
|
|
assert(ret.first == s.find(0));
|
|
assert(ret.second == true);
|
|
|
|
//item already present:
|
|
//nothing is done and returns false on the pair
|
|
ret = s.insert(1);
|
|
assert(ret.first == s.find(1));
|
|
assert(ret.second == false);
|
|
|
|
std::set<int> s1 = {0, 1, 2};
|
|
assert(s == s1);
|
|
}
|
|
|
|
/*
|
|
# erase
|
|
|
|
Remove element from set.
|
|
|
|
Returns number of elements removed.
|
|
*/
|
|
{
|
|
std::set<int> s = {0, 1, 2};
|
|
|
|
assert(s.erase(1) == 1);
|
|
std::set<int> s2 = {0, 2};
|
|
assert(s == s2);
|
|
|
|
assert(s.erase(1) == 0);
|
|
}
|
|
|
|
// ERROR no random access since it uses bidirection iterator.
|
|
{
|
|
//cout << s[0] << endl;
|
|
}
|
|
|
|
//size
|
|
{
|
|
std::set<int> s;
|
|
assert(s.size() == 0);
|
|
s.insert(0);
|
|
assert(s.size() == 1);
|
|
}
|
|
|
|
/*
|
|
iterate
|
|
|
|
Biderectional iterator.
|
|
|
|
Always sorted.
|
|
*/
|
|
|
|
/*
|
|
find
|
|
|
|
If found, returns an iterator pointing to the element.
|
|
Else, returns `map::end()`
|
|
|
|
find is `log n` time since the container is ordered.
|
|
|
|
log n time complexity since always sorted
|
|
*/
|
|
{
|
|
std::set<int> s = {0, 1, 2};
|
|
std::set<int>::iterator it;
|
|
|
|
it = s.find(1);
|
|
assert(*it == 1);
|
|
|
|
it = s.find(3);
|
|
assert(it == s.end());
|
|
}
|
|
|
|
/*
|
|
count
|
|
|
|
Count how many times an item is in the set.
|
|
|
|
Can only return 1 or 0.
|
|
|
|
Equivalent to doing a find.
|
|
*/
|
|
{
|
|
std::set<int> s = {1, 2, 0, 1};
|
|
assert(s.count(1) == 1);
|
|
assert(s.count(3) == 0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
# hashmap
|
|
|
|
There seems to be no explicit hashmap container, only a generic map interface,
|
|
|
|
See map.
|
|
|
|
Nonstandard `hash_map` already provided with gcc and msvc++.
|
|
It is placed in the `std::` namespace, but it is *not* ISO.
|
|
|
|
# map
|
|
|
|
<http://www.cplusplus.com/reference/map/map/>
|
|
|
|
Also comes in an unordered version `unordered_map`.
|
|
|
|
Ordered.
|
|
|
|
Also comes in an multiple value input version `multimap`.
|
|
|
|
Does not require a hash function. Usually implemented as a self balancing tree such as a rb tree.
|
|
|
|
# unordered_map
|
|
|
|
TODO complexity comparison to map.
|
|
*/
|
|
{
|
|
/*
|
|
The initializer list constructor makes things very easy.
|
|
*/
|
|
{
|
|
std::map<int,std::string> m{
|
|
{0, "zero"},
|
|
{1, "one"},
|
|
{2, "two"},
|
|
};
|
|
}
|
|
|
|
/*
|
|
emplace
|
|
|
|
put a value pair into the map without creating the pair explicitly
|
|
|
|
needs gcc 4.8: <http://stackoverflow.com/questions/15812276/stdset-has-no-member-emplace>
|
|
*/
|
|
{
|
|
//std::map<int,std::string> m;
|
|
//m.emplace(0, "zero");
|
|
//m.emplace(1, "one");
|
|
//m.emplace(2, "two");
|
|
}
|
|
|
|
/*
|
|
# insert
|
|
|
|
Insert pair into map.
|
|
|
|
The return value is similar to that of a set insertion with respec to the key.
|
|
*/
|
|
{
|
|
std::map<int,std::string> m;
|
|
std::pair<std::map<int,std::string>::iterator,bool> ret;
|
|
|
|
ret = m.insert(std::pair<int,std::string>(0, "zero"));
|
|
assert(ret.first == m.find(0));
|
|
assert(ret.second == true);
|
|
|
|
ret = m.insert(std::pair<int,std::string>(1, "one"));
|
|
assert(ret.first == m.find(1));
|
|
assert(ret.second == true);
|
|
|
|
//key already present
|
|
ret = m.insert(std::pair<int,std::string>(1, "one2"));
|
|
assert(m[1] == "one");
|
|
assert(ret.first == m.find(1));
|
|
assert(ret.second == false);
|
|
}
|
|
|
|
/*
|
|
iterate
|
|
|
|
Map is ordered.
|
|
|
|
It is iterated in key `<` order.
|
|
|
|
Iteration returns key value pairs.
|
|
*/
|
|
{
|
|
std::map<int,std::string> m{
|
|
{1, "one"},
|
|
{0, "zero"},
|
|
};
|
|
|
|
int i = 0;
|
|
int is[] = {0, 1};
|
|
for (auto& im : m) {
|
|
assert(im.first == is[i]);
|
|
//cout << im->second << endl;
|
|
++i;
|
|
}
|
|
assert(i == 2);
|
|
assert(map_to_str(m) == "0:zero, 1:one, ");
|
|
}
|
|
|
|
/*
|
|
[] operator
|
|
|
|
get value from a given key
|
|
|
|
WARNING: if the key does not exist, it is inserted with a value with default constructor.
|
|
|
|
This can be avoided by using `find` instead of `[]`.
|
|
*/
|
|
{
|
|
std::map<int,std::string> m{
|
|
{0, "zero"},
|
|
{1, "one"},
|
|
};
|
|
|
|
assert(m[0] == "zero");
|
|
assert(m[1] == "one");
|
|
|
|
//inserts `(3,"")` because `""` is the value for the default string constructor
|
|
assert(m[2] == "");
|
|
assert(m.size() == 3);
|
|
}
|
|
|
|
/*
|
|
# find #check if in map
|
|
|
|
Similar to `std::set` find with respect to the keys:
|
|
returns an iterator pointing to the pair which has given key, not the value.
|
|
|
|
If not found, returns `map::end()`
|
|
|
|
This is perferrable to `[]` since it does not insert non-existent elements.
|
|
*/
|
|
{
|
|
std::map<int,std::string> m{
|
|
{0, "zero"},
|
|
{1, "one"},
|
|
};
|
|
|
|
assert(m.find(0)->second == "zero");
|
|
assert(m.find(1)->second == "one");
|
|
|
|
assert(m.find(2) == m.end());
|
|
assert(m.size() == 2);
|
|
}
|
|
|
|
/*
|
|
erase
|
|
|
|
Remove element from map.
|
|
|
|
Returns number of elements removed.
|
|
*/
|
|
{
|
|
int ret;
|
|
|
|
std::map<int,std::string> m{
|
|
{0, "zero"},
|
|
{1, "one"},
|
|
};
|
|
|
|
std::map<int,std::string> m2;
|
|
m2.insert(std::pair<int,std::string>(0, "zero"));
|
|
|
|
ret = m.erase(1);
|
|
assert(ret = 1);
|
|
|
|
assert(m == m2);
|
|
|
|
ret = m.erase(1);
|
|
assert(ret == 0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
# list
|
|
|
|
Doubly linked list.
|
|
|
|
Advantages over std::vector: fast inservion and removal from middle.
|
|
|
|
Unless you really need those operations fast, don't use this data structure.
|
|
|
|
No random access.
|
|
|
|
# forward_list
|
|
|
|
Like list, but singly linked, and therefore not backwards interable.
|
|
*/
|
|
{
|
|
//initializer list constructor
|
|
{
|
|
std::list<int> l{0, 1};
|
|
}
|
|
|
|
// # emplace
|
|
{
|
|
std::list<int> l{0, 1};
|
|
l.emplace(++l.begin(), 2);
|
|
assert(l == std::list<int>({0, 2, 1}));
|
|
}
|
|
|
|
// # remove: remove all elements with a given value from list
|
|
{
|
|
std::list<int> l{0, 1, 0, 2};
|
|
l.remove(0);
|
|
assert(l == std::list<int>({1, 2}));
|
|
}
|
|
|
|
// # splice: transfer elements from one list to another
|
|
{
|
|
std::list<int> l{0, 1};
|
|
std::list<int> l2{2, 3};
|
|
l.splice(++l.begin(), l2);
|
|
assert(l == std::list<int>({0, 2, 3, 1}));
|
|
assert(l2 == std::list<int>());
|
|
}
|
|
}
|
|
|
|
/*
|
|
# iterator
|
|
|
|
Iteration could be done with random access in certain data structures with a for i loop.
|
|
|
|
Iterators are better becase you can also use them for structures without random access,
|
|
so if you decide to change structures in the future the job will be much easier.
|
|
|
|
# iterator categories
|
|
|
|
Iterators are categorized depending on the operations they can do:
|
|
|
|
<http://www.cplusplus.com/reference/iterator/>
|
|
|
|
The clases are (from least to most versatile):
|
|
|
|
- Input Output
|
|
- Forward
|
|
- Bidirectional
|
|
- Random Access
|
|
|
|
The most versatile iterators (random access) behave much like pointers,
|
|
and overload most pointer operations such as integer increment `it + 1` and
|
|
pointer dereference `*it` in a similar way to pointers.
|
|
|
|
Those classes are not language enforced via inheritance like in Java,
|
|
but could be used by programmers to implement typedefs that explain
|
|
the types of operations permitted. So if you are going to use a typedef
|
|
solution not to tie yourself to a given container, consider naming the
|
|
typdefed as one of the classes to indicate the operationt can do:
|
|
|
|
typedef random_it std::vector<int>::iterator;
|
|
|
|
It is possible to retreive the class of an interator via `std::iterator_traits<ITER>::interator_category`.
|
|
*/
|
|
{
|
|
// Before C++11: begin and end were the only way to use iterators.
|
|
// After C++11; the range based syntax is the best way to use them.
|
|
{
|
|
/*
|
|
# forward iteration
|
|
|
|
Can be done on all containers.
|
|
|
|
# begin
|
|
|
|
Returns an iterator to the first element.
|
|
|
|
# end
|
|
|
|
Returns an iterator to the first element *after* the last.
|
|
*/
|
|
{
|
|
std::vector<int> v{1, 2, 0};
|
|
int i = 0;
|
|
int is[]{1, 2, 0};
|
|
|
|
for (auto it = v.begin(); it != v.end(); ++it) {
|
|
assert(*it == is[i]);
|
|
++i;
|
|
}
|
|
}
|
|
|
|
/*
|
|
# backwards iteration
|
|
|
|
Can only be done on biderectional containers.
|
|
|
|
# rbegin
|
|
|
|
Reversed begin.
|
|
|
|
Returns a `reverse_iterator` that points to the last emlement.
|
|
|
|
++ on reversed iterators decreases them.
|
|
|
|
# rend
|
|
|
|
Returns a reversed iterator to the element before the first.
|
|
*/
|
|
{
|
|
std::vector<int> v{1, 2, 0};
|
|
int i;
|
|
int is[]{1, 2, 0};
|
|
|
|
i = 2;
|
|
for (auto it = v.rbegin(); it != v.rend(); ++it) {
|
|
assert(*it == is[i]);
|
|
//cout << *it << endl;
|
|
--i;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
# range based for loop #foreach
|
|
|
|
C++11
|
|
|
|
Like python foreach or Java improved-for loop.
|
|
|
|
This is the best way to iterate a container with C++11.
|
|
|
|
Much easier to write or read.
|
|
|
|
Also have the advantage that you don't need to specify iterator type!
|
|
|
|
Behind the scenes, this method is still based on iterators,
|
|
and the class to be iterated needs to implement:
|
|
|
|
- begin()
|
|
- end()
|
|
|
|
And the iterator returned must implement:
|
|
|
|
- operator++()
|
|
- operator!=()
|
|
- operator*()
|
|
*/
|
|
{
|
|
#if __cplusplus >= 201103L
|
|
//forward
|
|
{
|
|
// If `int&` is used, no useless copies are made.
|
|
// and the vector can be modified directly.
|
|
{
|
|
std::vector<int> v{1, 2, 0};
|
|
int is[]{1, 2, 0};
|
|
int i = 0;
|
|
for (int& iv : v) {
|
|
assert(iv == is[i]);
|
|
//cout << iv << endl;
|
|
iv++;
|
|
i++;
|
|
}
|
|
assert((v == std::vector<int>{2, 3, 1}));
|
|
}
|
|
|
|
// Without `&`, makes copies of each element.
|
|
// Usually not what we want.
|
|
{
|
|
std::vector<int> v{1, 2, 0};
|
|
int is[]{1, 2, 0};
|
|
int i = 0;
|
|
for (int iv : v) {
|
|
assert(iv == is[i]);
|
|
//cout << iv << endl;
|
|
iv++;
|
|
i++;
|
|
}
|
|
assert((v == std::vector<int>{1, 2, 0}));
|
|
}
|
|
|
|
// Less code duplication with auto.
|
|
// This is the best way to do it.
|
|
{
|
|
std::vector<int> v{1, 2, 0};
|
|
int is[]{1, 2, 0};
|
|
int i = 0;
|
|
for (auto& iv : v) {
|
|
assert(iv == is[i]);
|
|
//cout << *it << endl;
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
# range based for loop for arrays
|
|
|
|
Also works for bare arrays for which the size is known at compile time!
|
|
*/
|
|
{
|
|
{
|
|
int is[]{1, 2};
|
|
for (int& i : is) {
|
|
i *= 2;
|
|
}
|
|
assert(is[0] == 2);
|
|
assert(is[1] == 4);
|
|
}
|
|
|
|
/*
|
|
does not work for dynamic memory since
|
|
there would be no way to know the array size at compile time
|
|
*/
|
|
{
|
|
//int *is = new int[2];
|
|
//is[0] = 1;
|
|
//is[0] = 2;
|
|
//for (int &i : is) {
|
|
// i *= 2;
|
|
//}
|
|
//delete[] is;
|
|
}
|
|
}
|
|
#endif
|
|
/*
|
|
backwards
|
|
|
|
TODO possible? Seems not out of the C++11 box: <http://stackoverflow.com/questions/8542591/c11-reverse-range-based-for-loop>
|
|
|
|
Auto is a lifesaver here to avoid typing the iterator type.
|
|
*/
|
|
{
|
|
std::vector<int> v = {1, 2, 0};
|
|
int i;
|
|
int is[] = {1, 2, 0};
|
|
|
|
//forward
|
|
{
|
|
i = 2;
|
|
for (auto it = v.rbegin(); it != v.rend(); ++it) {
|
|
assert(*it == is[i]);
|
|
//cout << *it << endl;
|
|
i--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
# generic containers
|
|
|
|
There is no standard iterator independent from container.
|
|
|
|
This can be done via type erasure techinques.
|
|
|
|
But would mean loss of performance because of lots of polymorphic calls
|
|
and stdlib is obssessed with performance.
|
|
|
|
The best solution seems to use typedefs:
|
|
|
|
typedef it_t std::vector<int>::iterator;
|
|
|
|
And then if ever your container changes all you have to do is modify one single typedef:
|
|
|
|
typedef it_t set<int>::iterator;
|
|
|
|
TODO isnt auto and range based for a better solution in c++11?
|
|
*/
|
|
{
|
|
std::vector<int> v{1, 2};
|
|
std::set<int> s{1, 2};
|
|
std::vector<int>::iterator itVec(v.begin());
|
|
std::set<int>::iterator itSeti(s.begin());
|
|
|
|
// Does not exist:
|
|
|
|
//iterator<int> itVec = v.begin();
|
|
//iterator<int> itSeti = s.begin();
|
|
|
|
// Best workaround is using auto:
|
|
|
|
auto vit(v.begin());
|
|
auto sit(v.begin());
|
|
}
|
|
|
|
// No born checking is done
|
|
{
|
|
std::vector<int> v{1, 2};
|
|
|
|
// Last element.
|
|
*(v.end() - 1);
|
|
|
|
// After last element no born check.
|
|
*(v.end());
|
|
|
|
// No such method.
|
|
//(v.end().hasNext());
|
|
}
|
|
|
|
/*
|
|
Base pointers and arrays can be used anywhere iterators can.
|
|
|
|
The stdlib functions have specializations for pointers.
|
|
|
|
<http://stackoverflow.com/questions/713309/c-stl-can-arrays-be-used-transparently-with-stl-functions>
|
|
*/
|
|
{
|
|
int is[]{2, 0, 1};
|
|
int j = 0;
|
|
for (auto& i : is) {
|
|
assert(i == is[j]);
|
|
j++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
# size_t for slt containers
|
|
|
|
See size_type.
|
|
|
|
# size_type
|
|
|
|
Random access containers such as std::vectors, strings, etc have a `size_type` member typedef
|
|
that represents a type large enough to hold its indexes.
|
|
|
|
For arrays, this type is exactly the C `size_t`.
|
|
|
|
For a std::vector, it will also probably be `size_t`, since std::vectors are array backed,
|
|
but using `size_type` gives more generality.
|
|
|
|
This type is returned by methods such as `size()`.
|
|
*/
|
|
{
|
|
std::vector<int> v{2, 0, 1};
|
|
std::vector<int>::size_type i(1);
|
|
v[i] = 1;
|
|
}
|
|
|
|
/*
|
|
# iterator_traits
|
|
|
|
Contain information about iterators.
|
|
|
|
This allows to create template functions that take generic iterators independent of the
|
|
exact container type as is the case for many function sunder `<algorithm>`.
|
|
*/
|
|
{
|
|
//value_type
|
|
//pointer
|
|
//reference
|
|
{
|
|
typedef std::iterator_traits<std::vector<int>::iterator>::value_type ValueType;
|
|
typedef std::iterator_traits<std::vector<int>::iterator>::pointer Pointer;
|
|
typedef std::iterator_traits<std::vector<int>::iterator>::reference Reference;
|
|
assert(typeid(ValueType) == typeid(int));
|
|
assert(typeid(Pointer) == typeid(int*));
|
|
assert(typeid(Reference) == typeid(int&));
|
|
}
|
|
|
|
/*
|
|
# difference_type
|
|
|
|
The type returned on a difference between two pointers.
|
|
|
|
Unlike size_type, this value is signed, since the difference may well be negative.
|
|
*/
|
|
{
|
|
typedef typename std::iterator_traits<std::vector<int>::iterator>::difference_type DifferenceType;
|
|
std::vector<int> v{0, 1};
|
|
assert(typeid(v.end() - v.begin()) == typeid(DifferenceType));
|
|
}
|
|
|
|
/*
|
|
# iterator_category
|
|
|
|
iterator_category is a struct *type*, not a value.
|
|
|
|
Therefore, in order to compare it one must use `typeid`.
|
|
*/
|
|
{
|
|
assert(typeid(std::iterator_traits<std::vector<int>::iterator>::iterator_category)
|
|
== typeid(std::random_access_iterator_tag));
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
# valarray
|
|
|
|
Array of values. Wors much like a mathematical vector.
|
|
|
|
Container that overloads many mathematical operations in a similar way to what Fortran does,
|
|
which may be more efficient and convenient.
|
|
|
|
Very obscure, for several reasons:
|
|
|
|
- other techniques achieve what it achieves
|
|
- low compiler support
|
|
|
|
Downsides compared to vectors:
|
|
|
|
- not resizable, so no push_back
|
|
|
|
<http://stackoverflow.com/questions/1602451/c-valarray-vs-vector>
|
|
*/
|
|
{
|
|
std::valarray<int> v;
|
|
std::valarray<int> v0{0, 1, 2};
|
|
std::valarray<int> v1{3, 4, 5};
|
|
|
|
assert(v0.sum() == 3);
|
|
assert(v0.min() == 0);
|
|
assert(v0.max() == 2);
|
|
|
|
/*
|
|
v = v0;
|
|
v.cshift(1);
|
|
assert((v == std::valarray<int>{1, 2, 0}).min());
|
|
*/
|
|
|
|
// == is elementwise equality.
|
|
//
|
|
// For equality of all elements, do `.min() == true`
|
|
{
|
|
std::valarray<int> v0{0, 1, 2};
|
|
std::valarray<int> v1{0, 2, 2};
|
|
assert(((v0 == v1) == std::valarray<bool>{true, false, true}).min());
|
|
|
|
}
|
|
|
|
// +, -, *, /, etc are overloaded elementwise.
|
|
//
|
|
// They are also overloaded for contained data type.
|
|
{
|
|
assert((v0 + v1 == std::valarray<int>{3, 5, 7}).min());
|
|
assert((v0 + 1 == std::valarray<int>{1, 2, 3}).min());
|
|
}
|
|
|
|
// Basic cmath functions are overloaded for valarray elementwise.
|
|
{
|
|
assert((abs(std::valarray<int>{-1, 0, 1}) == std::valarray<int>{1, 0, 1}).min());
|
|
assert((pow(std::valarray<int>{-2, 0, 2}, 2) == std::valarray<int>{4, 0, 4}).min());
|
|
}
|
|
}
|
|
|
|
// # algorithm
|
|
{
|
|
{
|
|
assert(std::min(0.1, 0.2) == 0.1);
|
|
assert(std::max(0.1, 0.2) == 0.2);
|
|
}
|
|
|
|
// # sort
|
|
{
|
|
std::vector<int> v{2, 0, 1};
|
|
std::sort(v.begin(), v.end());
|
|
std::vector<int> v1 = {0, 1, 2};
|
|
assert((v == std::vector<int>{0, 1, 2}));
|
|
}
|
|
|
|
// # reverse
|
|
{
|
|
std::vector<int> v{2, 0, 1};
|
|
std::reverse(v.begin(), v.end());
|
|
assert((v == std::vector<int>{1, 0, 2}));
|
|
}
|
|
|
|
/*
|
|
# swap
|
|
|
|
Does things equivalent to:
|
|
|
|
template <class T> void swap (T& a, T& b)
|
|
{
|
|
T c(a); a=b; b=c;
|
|
}
|
|
|
|
However stdlib can specialize it to do operations more efficiently.
|
|
|
|
Some stdlib classes implement swap as a method.
|
|
|
|
Particularly important because of the copy and swap idiom.
|
|
*/
|
|
|
|
// # randomize
|
|
{
|
|
std::vector<int> v{2, 0, 1};
|
|
std::random_shuffle(v.begin(), v.end());
|
|
}
|
|
|
|
// # copy
|
|
{
|
|
std::vector<int> v{2, 0, 1};
|
|
std::vector<int> v2(5, 3);
|
|
std::copy(v.begin(), v.end(), v2.begin() + 1);
|
|
assert(v2 == std::vector<int>({3, 2, 0, 1, 3}));
|
|
}
|
|
|
|
/*
|
|
# equal
|
|
|
|
Compares ranges of two containers.
|
|
*/
|
|
{
|
|
std::vector<int> v {0, 1, 2 };
|
|
std::vector<int> v2{ 1, 2, 3};
|
|
assert(std::equal(v.begin() + 1, v.end(), v2.begin()));
|
|
}
|
|
|
|
/*
|
|
# accumulate
|
|
|
|
Sum over range.
|
|
|
|
Also has functional versions <http://www.cplusplus.com/reference/numeric/accumulate/>
|
|
*/
|
|
{
|
|
std::vector<int> v{2, 0, 1};
|
|
assert(std::accumulate(v.begin(), v.end(), 0) == 3);
|
|
assert(std::accumulate(v.begin(), v.end(), 10) == 13);
|
|
}
|
|
|
|
/*
|
|
# find
|
|
|
|
Return iterator to first found element.
|
|
*/
|
|
{
|
|
std::vector<int> v{2,0,1};
|
|
unsigned int pos;
|
|
|
|
pos = std::find(v.begin(), v.end(), 0) - v.begin();
|
|
assert(pos == 1);
|
|
|
|
pos = std::find(v.begin(), v.end(), 1) - v.begin();
|
|
assert(pos == 2);
|
|
|
|
pos = std::find(v.begin(), v.end(), 2) - v.begin();
|
|
assert(pos == 0);
|
|
|
|
pos = std::find(v.begin(), v.end(), 3) - v.begin(); //end() returned
|
|
assert(pos == v.size());
|
|
}
|
|
|
|
/*
|
|
# find_if
|
|
|
|
Like find, but using an arbitrary condition on each element instead of equality.
|
|
|
|
Consider usage with C++11 lambdas and functional.
|
|
*/
|
|
{
|
|
std::vector<int> v{2, 0, 1};
|
|
assert(std::find_if (v.begin(), v.end(), odd) == --v.end());
|
|
}
|
|
|
|
/*
|
|
# binary_search
|
|
|
|
Container must be already sorted.
|
|
|
|
Log complexity.
|
|
|
|
Only states if the element is present or not, but does not get its position.
|
|
|
|
If you want to get the position of those items, use `equal_range`, `lower_bound` or `upper_bound`.
|
|
*/
|
|
{
|
|
|
|
std::vector<int> v{0, 1, 2};
|
|
assert(std::binary_search(v.begin(), v.end(), 1) == true);
|
|
assert(std::binary_search(v.begin(), v.end(), 3) == false);
|
|
assert(std::binary_search(v.begin(), v.end() - 1, 2) == false);
|
|
}
|
|
|
|
/*
|
|
# lower_bound
|
|
|
|
Finds first element in container which is not less than val.
|
|
*/
|
|
{
|
|
std::vector<int> v{0, 2, 3};
|
|
auto it = std::lower_bound(v.begin(), v.end(), 1);
|
|
assert(it - v.begin() == 1);
|
|
}
|
|
|
|
/*
|
|
# upper_bound
|
|
|
|
Finds first element in container is greater than val.
|
|
*/
|
|
{
|
|
std::vector<int> v{0, 1, 2};
|
|
auto it = std::upper_bound(v.begin(), v.end(), 1);
|
|
assert(it - v.begin() == 2);
|
|
}
|
|
|
|
/*
|
|
# equal_range
|
|
|
|
Finds first and last location of a value iniside a ranged container.
|
|
|
|
Return values are the same as lower_bound and upper_bound.
|
|
|
|
log complexity.
|
|
*/
|
|
{
|
|
std::vector<int> v{0, 1, 1, 2};
|
|
std::vector<int>::iterator begin, end;
|
|
std::tie(begin, end) = std::equal_range(v.begin(), v.end(), 1);
|
|
assert(begin - v.begin() == 1);
|
|
assert(end - v.begin() == 3);
|
|
}
|
|
|
|
// # count
|
|
{
|
|
std::vector<int> v{2,1,2};
|
|
assert(std::count(v.begin(), v.end(), 0) == 0);
|
|
assert(std::count(v.begin(), v.end(), 1) == 1);
|
|
assert(std::count(v.begin(), v.end(), 2) == 2);
|
|
}
|
|
|
|
|
|
// # max_element #min_element
|
|
{
|
|
std::vector<int> v{2,0,1};
|
|
assert(*std::max_element(v.begin(), v.end()) == 2);
|
|
assert(*std::min_element(v.begin(), v.end()) == 0);
|
|
}
|
|
|
|
/*
|
|
# advance
|
|
|
|
Advance iterator by given number.
|
|
|
|
If random access, simply adds + N.
|
|
|
|
Else, calls `++` N times.
|
|
|
|
Advantage over `+`: only random access containers support `+`,
|
|
but this works for any container, allowing one to write more general code.
|
|
|
|
Beware however that this operation will be slow for non random access containers.
|
|
*/
|
|
{
|
|
std::vector<int> v{0, 1, 2};
|
|
auto it = v.begin();
|
|
std::advance(it, 2);
|
|
assert(*it == 2);
|
|
}
|
|
|
|
#if __cplusplus >= 201103L
|
|
/*
|
|
# next
|
|
|
|
Same as advance, but returns a new iterator instead of modifying the old one.
|
|
*/
|
|
{
|
|
std::vector<int> v{0, 1, 2};
|
|
auto it(v.begin());
|
|
auto itNext = std::next(it, 2);
|
|
assert(*it == 0);
|
|
assert(*itNext == 2);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
# priority queue
|
|
|
|
Offers `O(1)` access to the smalles element.
|
|
|
|
Other operatoins vary between `O(n)` and `O(1).
|
|
|
|
Most common implementaions are via:
|
|
|
|
- binary heap
|
|
- fibonacci heap
|
|
|
|
Boost offers explicit heap types: fibonacci, binary and others.
|
|
|
|
But no guarantees are made.
|
|
|
|
As of C++11, does not support the increase key operation.
|
|
|
|
A binary heap without increase key can be implemented via the heap function family under algorithm.
|
|
*/
|
|
|
|
/*
|
|
# heap
|
|
|
|
Binary heap implementation.
|
|
|
|
<http://en.wikipedia.org/wiki/Heap_%28data_structure%29>
|
|
|
|
In short:
|
|
|
|
- getting largest element is O(1)
|
|
- removing the largest element is O(lg) for all implementation
|
|
- other operations (insertion) may be O(1) or O(lg) depending on the implementation.
|
|
|
|
this makes for a good priority queue.
|
|
Exact heap type is not guaranteed. As of 2013, it seems that most implementations use binary heaps.
|
|
|
|
For specific heaps such as Fibonacci, consider [Boost](http://www.boost.org/doc/libs/1_49_0/doc/html/heap.html).
|
|
|
|
<http://stackoverflow.com/questions/14118367/stl-for-fibonacci-heap>
|
|
|
|
There is no concrete heap data structure in C++:
|
|
only heap operations over random access data structures.
|
|
This is why this is under algoritms and is not a data structure of its own.
|
|
|
|
There is however a `priority_queue` stdlib container.
|
|
|
|
Why random access structure is needed: <https://github.com/cirosantilli/comp-sci/blob/1.0/src/heap.md#array-implementation>
|
|
*/
|
|
{
|
|
int myints[]{10, 20, 30, 5, 15};
|
|
std::vector<int> v(myints, myints + 5);
|
|
|
|
/*
|
|
# make_heap
|
|
|
|
Make random access data structure into a heap.
|
|
|
|
This changes the element order so that the range has heap properties
|
|
|
|
Worst case time: $O(n)$.
|
|
*/
|
|
std::make_heap(v.begin(), v.end());
|
|
assert(v.front() == 30);
|
|
|
|
/*
|
|
# pop_heap
|
|
|
|
Remove the largest element from the heap.
|
|
|
|
That element is moved to the end of the data structure, but since the
|
|
heap should have its length reduced by one, that element will then be out of the heap.
|
|
|
|
Assumes that the input range is already a heap (made with `make_heap` for example).
|
|
*/
|
|
std::pop_heap(v.begin(), v.end());
|
|
|
|
//the element still exists on the data structure
|
|
assert(v.back() == 30);
|
|
|
|
//the second largest element hat become the largets
|
|
assert(v.front() == 20);
|
|
|
|
//remove the element from the data structure definitively
|
|
v.pop_back();
|
|
|
|
/*
|
|
# push_heap
|
|
|
|
Insert element into a heap.
|
|
|
|
Assumes that:
|
|
|
|
- the range 0 - (end - 1) was already a heap
|
|
- the new element to be inserted into that heap is at end.
|
|
*/
|
|
|
|
//add the new element to the data structure
|
|
v.push_back(99);
|
|
|
|
//reorganize the data so that the last element will be placed in the heap
|
|
std::push_heap(v.begin(), v.end());
|
|
|
|
assert(v.front() == 99);
|
|
|
|
/*
|
|
# sort_heap
|
|
|
|
Assumes that the input range is a heap, and sorts it in increasing order.
|
|
|
|
The assumption that we have a heap allows for $O(ln)$ sorting,
|
|
much faster than the optimal bound $O(n log n)$.
|
|
|
|
This is exactly what the heapsort alrotithm does: make_heap and then sort_heap.
|
|
*/
|
|
|
|
std::sort_heap(v.begin(), v.end());
|
|
//assert(v)
|
|
//v == 5 10 15 20 99
|
|
}
|
|
}
|
|
|
|
#if __cplusplus >= 201103L
|
|
/*
|
|
# functional
|
|
|
|
Do magic with functions.
|
|
|
|
Useful with stdlib functions that take functions as arguments.
|
|
*/
|
|
{
|
|
/*
|
|
# bind2nd
|
|
|
|
Tranform a function that takes two arguments into a function that takes only the first.
|
|
|
|
Useful with stdlib functions that must take functions that take a single argument,
|
|
but you want to pass an extra parameter to that function.
|
|
|
|
TODO0 get working
|
|
*/
|
|
{
|
|
/*
|
|
std::vector<int> v = {2, 0, 1};
|
|
assert(std::find_if (
|
|
v.begin(),
|
|
v.end(),
|
|
std::bind2nd([](int i, int param){return i == param + 1;}, 1)
|
|
) == v.begin());
|
|
*/
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
# hash
|
|
|
|
<http://www.cplusplus.com/reference/functional/hash/>
|
|
|
|
The stdlib furnishes overloaded hash functions for stdlib containers.
|
|
|
|
Those functions are implemented as callable classes that implement `()`.
|
|
|
|
For base types, those hashes are found under the `functional`.
|
|
|
|
For std::vectors, only `std::vector<bool>` has a template.
|
|
|
|
For other types, they are found in the same header that defines those types:
|
|
ex: hash for std::vectors is under `<vector>`.
|
|
|
|
Returns a `size_t` result.
|
|
*/
|
|
{
|
|
std::cout << "hash" << std::endl;
|
|
std::cout << " 1 = " << std::hash<int>()(1) << std::endl;
|
|
std::cout << " string abc = " << std::hash<std::string>()("abc") << std::endl;
|
|
}
|
|
|
|
#if __cplusplus >= 201103L
|
|
/*
|
|
# regex
|
|
|
|
Finally they are supported!
|
|
|
|
Many types are supported: Javascript, grep, awk, ...
|
|
|
|
It is probably saner and more powerful to stick to Javascript regexes.
|
|
*/
|
|
{
|
|
// Js has `[:d:]` equivalent POSIX `[:digit:]`.
|
|
std::regex r("a.(c|d)");
|
|
}
|
|
#endif
|
|
|
|
// # memory
|
|
{
|
|
#if __cplusplus >= 201103L
|
|
/*
|
|
# shared_ptr
|
|
|
|
Introuced in C++11.
|
|
|
|
Before that as part of boost.
|
|
*/
|
|
{
|
|
{
|
|
callStack.clear();
|
|
std::shared_ptr<NoBaseNoMember> spi1(new NoBaseNoMember);
|
|
std::shared_ptr<NoBaseNoMember> spi2(spi1);
|
|
spi1->method();
|
|
spi1 = std::shared_ptr<NoBaseNoMember>(new NoBaseNoMember);
|
|
spi2 = std::shared_ptr<NoBaseNoMember>(spi1);
|
|
assert(callStack.back() == "NoBaseNoMember::~NoBaseNoMember()");
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if __cplusplus >= 201103L
|
|
/*
|
|
# thread #multithreading #parallel #concurrency
|
|
|
|
Requires `-pthread` flag on g++ Linux.
|
|
*/
|
|
{
|
|
// Start threads.
|
|
std::thread t1(threadFunc, 1000);
|
|
std::thread t2(threadFunc, 1000);
|
|
|
|
// Ensure that both threads ended.
|
|
t1.join();
|
|
t2.join();
|
|
|
|
assert(threadChange > 0);
|
|
//assert(threadIds.size() == 2);
|
|
//assert(threadGlobalEq0 > 0);
|
|
assert(threadGlobalMutexedEq0 == 0);
|
|
|
|
std::thread::id mainId = std::this_thread::get_id();
|
|
std::this_thread::sleep_for(std::chrono::nanoseconds(nNsecs));
|
|
std::this_thread::yield();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
# preprocessor
|
|
|
|
Almost the same as the C one:
|
|
http://stackoverflow.com/questions/5085533/is-a-c-preprocessor-identical-to-a-c-preprocessor
|
|
*/
|
|
{
|
|
/*
|
|
# standard preprocessor defines
|
|
*/
|
|
{
|
|
/*
|
|
# __cplusplus
|
|
|
|
Defined only if using C++ compiler.
|
|
|
|
Its value is the actual C++ version in use in a similar way to __STDC_VERSION__
|
|
|
|
Values:
|
|
|
|
- C98: 199711L
|
|
- C11: 201103L
|
|
*/
|
|
{
|
|
#ifdef __cplusplus
|
|
printf("__cplusplus = %li\n", __cplusplus);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
#if __cplusplus >= 201103L
|
|
/*
|
|
# Attributes
|
|
|
|
Implemented as extensions for a long time in GCC via `__attribtes__`
|
|
and in Microsoft with `#pragma`. Now some have been standardized!
|
|
|
|
Intended only for functions which don't change behaviour: only to help
|
|
compilers optimize or geneate better error messages.
|
|
|
|
<http://www.stroustrup.com/C++11FAQ.html#attributes>
|
|
|
|
Attributes can be defined for various objects, and there are 2 standard ones:
|
|
noreturn and carries_dependency
|
|
*/
|
|
{
|
|
try {
|
|
noreturn_func();
|
|
} catch (int i) {}
|
|
}
|
|
#endif
|
|
|
|
#ifdef PROFILE
|
|
loopOnlyProf(nProfRuns);
|
|
whileOnlyProf(nProfRuns);
|
|
|
|
intAssignProf(nProfRuns);
|
|
intSumProf(nProfRuns);
|
|
intSubProf(nProfRuns);
|
|
intMultProf(nProfRuns);
|
|
intDivProf(nProfRuns);
|
|
|
|
floatSumProf(nProfRuns);
|
|
floatSubProf(nProfRuns);
|
|
floatMultProf(nProfRuns);
|
|
floatDivProf(nProfRuns);
|
|
|
|
funcCallProf(nProfRuns);
|
|
inlineFuncCallProf(nProfRuns);
|
|
|
|
// Allocation.
|
|
{
|
|
stack1bProf(nProfRuns);
|
|
stack1kbProf(nProfRuns);
|
|
stack1mbProf(nProfRuns);
|
|
|
|
heapMalloc1bProf(nProfRuns);
|
|
heapMalloc1kbProf(nProfRuns);
|
|
//heapMalloc1mbProf(nProfRuns);
|
|
|
|
heapNew1bProf(nProfRuns);
|
|
heapNew1kbProf(nProfRuns);
|
|
// new is faster!
|
|
//heapNew1mbProf(nProfRuns);
|
|
}
|
|
|
|
methodCallProf(nProfRuns);
|
|
// 2x as expensive than function call
|
|
virtualMethodCallProf(nProfRuns);
|
|
|
|
// BAD: don't do stdout on profiling
|
|
// system time is not counted anyways
|
|
//putsProf(nProfRuns);
|
|
#endif
|
|
|
|
// # Design patterns
|
|
{
|
|
//VisibleInnerIterable
|
|
{
|
|
VisibleInnerIterable c;
|
|
VisibleInnerIterable::Iterable ita = c.getIterable();
|
|
VisibleInnerIterable::Iterable::iterator it = ita.begin();
|
|
|
|
int i;
|
|
int is[]{0,1,2};
|
|
for (
|
|
it = ita.begin(), i=0;
|
|
it != ita.end();
|
|
++it, ++i
|
|
)
|
|
{
|
|
assert(*it == is[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
# Idioms
|
|
|
|
Basically very small design patterns.
|
|
*/
|
|
{
|
|
/*
|
|
# Dynamic multi-dimensional array
|
|
|
|
Sources: <http://www.cplusplus.com/forum/articles/7459/>
|
|
|
|
In addition to C malloc like techniques, C++ also offers the simpler possibility of using std::vectors
|
|
which will automatically manage the memory allocation / dellocation for us.
|
|
|
|
The tradeoff is that this method will be potentially slower since it:
|
|
|
|
- requires constructor calls at non uniform initialization.
|
|
|
|
- may require function calls for the `[]` operator overload.
|
|
|
|
It is however likely that the compiler will inline those.
|
|
*/
|
|
{
|
|
// Given width and height.
|
|
{
|
|
int width = 2, height = 3;
|
|
std::vector<std::vector<int>> array_2d(height, std::vector<int>(width));
|
|
array_2d[0][0] = 1;
|
|
array_2d[2][1] = 5;
|
|
assert(array_2d[0][0] == 1);
|
|
assert(array_2d[0][1] == 0);
|
|
assert(array_2d[2][1] == 5);
|
|
}
|
|
|
|
// Uniform initialized.
|
|
{
|
|
std::vector<std::vector<int>> array_2d{
|
|
{0, 1},
|
|
{2, 3},
|
|
{4, 5},
|
|
};
|
|
assert(array_2d[0][0] == 0);
|
|
assert(array_2d[2][1] == 5);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
# main return
|
|
|
|
Like in C99, C++ return can omit the return, in which case it returns 0.
|
|
*/
|
|
|
|
std::cout << "ALL ASSERTS PASSED" << std::endl;
|
|
return EXIT_SUCCESS;
|
|
|
|
// global/static destructors happen at exit time.
|
|
}
|