C++11
This text also contains own comments and examples
std::vector<std::list<int>> myContainer;C++11 will recognize the difference to iostream operator ">>".
//old fashioned way using escape sequences: std::string filePathOld= "C:UserDataGeraldSW"; // use a raw string literal std::string filePathNew = R"(C:UserDataGeraldSW)";Raw string literals are more readable than the escaped strings.
// Initialize a pointer SomeClass* pSomeClass = nullptr;
Example:
enum class Color { RED, GREEN, BLUE };
Color color = Color::GREEN;
enum class Color;
Color color = static_cast<Color>(2); // -> BLUE int val = static_cast<int>(Color::GREEN); // -> 1
// Definition enum class Color : char {RED, GREEN, BLUE}; // The type has to be used also within forward declaration: enum class : char;
enum class Color { RED, // -> value 0 GREEN = 7, // -> value 7 BLUE // -> value 8 };
std::vector<int> container; // Define element with reference type to be able // to perform changes for (int & element : container) { element += 4; }
// assume there is a map containing for each // custumer id an according custumer name typedef std::map<int, std::string> Customers; void WriteCustomers(Customers const & in_customers) { for (auto customer: in_customers) { std::cout << customer.second << std::endl; } }The usage of auto releases you from using complexer code like
for (std::map<int,std::string>::value_type customer : in_customers) { std::cout << customer.second << std::endl; } // With use of typedef Customers the complex type could // also be simplified to Customers::value_type
Assuming you are not working on a trivial or prototype project (a "write once-change never" project), then probably you are forced to work with your code a couple of years. A single line of code is written once but perhaps you (or someone having to extend your code) has to read it multiple times during the development cycle. Is the reader as quick as the compiler to automatically assign the proper type information to 10 different auto variables used within a function?
// Assumption: you are needing a number of bits // and you want to use a basic integral type as storage const int NUM_USED_BITS = 18; // value may change during development typedef short int MyBitfieldType; // Check at compile time whether your bits // can be stored within your desired type static_assert(sizeof(MyBitfieldType)*8 >= NUM_USED_BITS, "MyBitfieldType cannot store all used bits, please choose bigger integral type");Usually a short int consists of 2 bytes and is able to store only 16 bits. Therefore the static_assert will generate the following compile error:
MySourceFile.cpp(670): error C2338: MyBitfieldType cannot store all used bits, please choose bigger integral type
class MyBaseClass { public: virtual ~MyBaseClass() {} virtual void SomeBaseMethod() = 0; }; class MyDerivedClass : public MyBaseClass { void SomeBaseMethod() override {}; }; // Macro to simplify writing #define CHECK_PROPERTY(EXPRESSION,TYPE) std::cout << #EXPRESSION "=" << std::EXPRESSION<TYPE>::value << std::endl; template <typename T> void CheckType() { std::cout << "nChecking type " << typeid(T).name() << std::endl; // RTTI info std::cout << "is_pod=" << std::is_pod<T>::value << std::endl; // with support of a macro less verbous: CHECK_PROPERTY(is_integral,T); CHECK_PROPERTY(is_class,T); CHECK_PROPERTY(is_function,T); CHECK_PROPERTY(is_abstract,T); CHECK_PROPERTY(is_polymorphic,T); CHECK_PROPERTY(has_virtual_destructor,T); }
int i = 14; MyDerivedClass derived; CheckType<int>(); CheckType<MyBaseClass>(); CheckType<MyDerivedClass>();
Checking type int is_pod=true is_integral=true is_class=false is_function=false is_abstract=false is_polymorphic=false has_virtual_destructor=false Checking type class MyBaseClass is_pod=false is_integral=false is_class=true is_function=false is_abstract=true is_polymorphic=true has_virtual_destructor=true Checking type class MyDerivedClass is_pod=false is_integral=false is_class=true is_function=false is_abstract=false is_polymorphic=true has_virtual_destructor=true
01 // MySourceFile.cpp 02 03 template <typename T> 04 void DoSomethingWithIntegral(T t) 05 { 06 static_assert(std::is_integral<T>::value, "please use an integral type"); 07 static_assert(!std::is_class<T>::value, "class type is not allowed here"); // do something useful 08 } 09 10 template <typename T> 11 void DoSomethingWithClass(T t) 12 { 13 static_assert(std::is_fundamental<T>::value == false, "fundamental type is not allowed here"); 14 static_assert(std::is_class<T>::value == true, "please use a class type"); // do something useful 15 }when compiling the following code:
39 ... 40 int i = 14; 41 MyDerivedClass derived; 42 43 DoSomethingWithIntegral(i); 44 DoSomethingWithIntegral(derived); 45 46 DoSomethingWithClass(i); 47 DoSomethingWithClass(derived);you will get the following compiler output:
MySourceFile.cpp c:MySourceFile.cpp(06): error C2338: please use an integral type c:MySourceFile.cpp(44) : see reference to function template instantiation 'void DoSomethingWithIntegralReferences: type traits, static_assert(T)' being compiled with [ T=MyDerivedClass ] c:MySourceFile.cpp(07): error C2338: class type is not allowed here c:MySourceFile.cpp(13): error C2338: fundamental type is not allowed here c:MySourceFile.cpp(46) : see reference to function template instantiation 'void DoSomethingWithClass (T)' being compiled with [ T=int ] c:MySourceFile.cpp(14): error C2338: please use a class type
struct Info { Info (std::string const & in_description, long in_value) : m_description (in_description) , m_value (in_value) {} std::string m_description; long m_value; };Then you can store references to it within a std::vector:
Info infoA ("Some Info A", 314); Info infoB ("Some Info B", 4711); // does not compile // std::vector<Info&> vRef; // wrapping reference works std::vector<std::reference_wrapper<Info>> vRef; // adding references to container vRef.push_back (std::ref(infoA)); vRef.push_back (infoB); // std::ref can be omitted // change infoA through reference (available through get()) vRef[0].get().m_description = "changed description"; //change through original instance infoA.m_value++; // proof that there is only one object instance assert (infoA.m_description == vRef[0].get().m_description); assert (infoA.m_value == vRef[0].get().m_value); assert (infoA.m_description == "changed description"); assert (infoA.m_value == 315);
With std::bind you can
bool SetResult (int in_resultCode, std::string const & in_context) { std::cout << "SetResult result=" << in_resultCode << " context=" << in_context << std::endl; return true; }Then you can bind this function to a changed signature:
// allow simple use of placeholders _1, _2, ... using namespace std::placeholders; // Define your function signature typedef std::function<bool(std::string const &, int)> MyResultFunc; // Bind the existing function to the new signature // and store the result in a std::function // (in this example the paramter order is reversed) MyResultFunc resultFunc = std::bind(SetResult, _2, _1); // call the stored function resultFunc ("only for test", 17);Output:
SetResult result=17 context=only for test
class MyCallbackObject { public: ~MyCallbackObject() { std::cout << "Destructor MyCallbackObject" << std::endl; } bool ReceiveResult (int in_resultCode, std::string const & in_context) { std::cout << "MyCallbackObject: result=" << in_resultCode << " context=" << in_context << std::endl; return true; // may return false e.g. to signal that the // result is no longer processed } };Then you can bind to member function ReceiveResult:
typedef std::function<bool(int)> MyCallbackFunc; MyCallbackObject cbo; // Using pointer to object to avoid creating temporary instances of cbo MyCallbackFunc cbFunc = std::bind( &MyCallbackObject::ReceiveResult, &cbo, // member function + object _1, // parameter "not set"); // preset for param // Simple syntax also works, but creates two temporary // instances of MyCallbackObject // MyCallbackFunc cbFunc2 = std::bind( // &MyCallbackObject::ReceiveResult, cbo, // _1, "not set"); // Reference to object also avoids creating temporary // instances of cbo // MyCallbackFunc cbFunc2 = std::bind( // &MyCallbackObject::ReceiveResult, std::ref(cbo), // _1, "not set"); ... // Finally call the stored member function cbFunc(42); }Output:
MyCallbackObject: result=42 context=not set
To make client code independent from those details you can hide the object and the reference counting within the stored std::function. From the client's point of view he simply calls a function and need not to bother about obejct validity and lifetime.
#include <memory> // shared_ptr class MyCallbackObject { ... }; typedef std::shared_ptr<MyCallbackObject>MyCallbackObjectSp;You can encapsulate the creation of the std::function containing a refcounted object:
MyCallbackFunc CreateCallbackFunc() { std::cout << "CreateCallbackFunc: Begin" << std::endl; // Create a callback object to receive some callback later in time MyCallbackObjectSp spCbo = std::make_shared<MyCallbackObject>(); // Pack a shared pointer to the callback object within the // std::function to keep the object alive MyCallbackFunc cbFunc = std::bind( &MyCallbackObject::ReceiveResult, spCbo, // member func, smart pointer _1, "not set"); std::cout << "CreateCallbackFunc: End" << std::endl; return cbFunc; // here the shared pointer spCbo goes out of scope // the only reference to the callback object // is contained within the std::function }Assume you have some client code function which finally calls back:
void DoSomethingAndSendResultViaCallback (MyCallbackFunc in_callbackFunc) { // do something std::this_thread::sleep_for(std::chrono::milliseconds(100)); // here nothing is visible about object and refcounting in_callbackFunc(89); }Concrete scenario using the code snippets from above:
MyCallbackFunc cbFunc = CreateCallbackFunc(); // Pass callback to asynchronoously // executed function // (in real code it may be the cient code // deciding to use a separate thread) std::thread t (DoSomethingAndSendResultViaCallback, cbFunc); cbFunc = MyCallbackFunc(); // release stored refcount std::cout << "local function object is reset without calling it" << std::endl; // Synchronize with thread execution t.join(); std::cout << "thread is joined" << std::endl;Output:
CreateCallbackFunc: Begin CreateCallbackFunc: End local function object is reset without calling it MyCallbackObject: result=89 context=not set // called from client thread Destructor MyCallbackObject // called from client thread thread is joined
storedFunc = MyCallbackFunc(); // -> destructing invisible callback object
std::list<int> values; int sum; std::for_each(values.begin(), values.end(), [&sum](int const & in_value){if (in_value > 0) sum+=in_value;}); std::cout << "nSum= " sum << std::endl;
std::vector<int> v; v.push_back(4); v.push_back(-4); v.push_back(17); v.push_back(2); v.push_back(67); v.push_back(7); auto itPos = std::find_if(v.begin(),v.end(), [](int const & num)->bool {return num > 15;}); // Simplified syntax is also possible: // auto itPos = std::find_if(v.begin(),v.end(), // [](int num){return num > 15;}); std::cout << "Found matching value " << *itPos << << " at position " << std::distance(v.begin(), itPos) << std::endl;Output:
Found matching value 17 at position 2
For more info see
lambda functions
Base class providing some virtual methods:
class Base { public: virtual void DoSomething (int); virtual int DoSomethingElse(double); };Derived class with overrides:
class Derived : public Base { // "override" ensures that there are matching base class methods // correct match with base class method virtual void DoSomething (int) override; // mismatch (wrong param type) -> compile error virtual int DoSomethingElse(int) override; };If the derived method does not have a matching base class method the compiler will say soemthing like:
error C3668: 'Derived::DoSomethingElse' : method with override specifier 'override' did not override any base class methods
Base class providing some virtual methods:
struct SomeInterface { virtual void DoSomething (int) = 0; virtual int DoSomethingElse (double) = 0; }; class Base : public SomeInterface { public: virtual void DoSomething (int) override; // this is the optimal implementation which cannot // be improved by derived classes virtual int DoSomethingElse(double) override final; };Derived class with overrides:
class Derived : public Base { // overriding is allowed virtual void DoSomething (int) override; // overriding is not allowed -> compile error virtual int DoSomethingElse(double) override; };If you are illegally trying to override a final method the compiler will say something like:
error C3248: 'Base::DoSomethingElse': function declared as 'final' cannot be overridden by 'Derived::DoSomethingElse'
class Derived final: public Base { };When trying to create a more derived class:
class MoreDerived : public Derived { };you will receive the following compile error:
error C3246: 'MoreDerived' : cannot inherit from 'Derived' as it has been declared as 'final'
class MyClass { public: // Ensure that the compiler generated // default cosntructor still exists // (despite of the definitions below which // would suppress the generation of the default // constructor) MyClass()=default; // Disallow copying via assignmment operator MyClass& operator= (MyClass const&)=delete; // Disallow copying via copy constructor MyClass (MyClass const&)=delete; };
class MyClass { public: // Disallow memory allocation on heap void* operator new (std::size_t)=delete; };
#include <ratio> typedef std::ratio<1,2> Num1; typedef std::ratio<1,3> Num2; typedef std::ratio_add<Num1, Num2> Sum; typedef std::ratio_multiply<Num1, Num2> Product; std::cout << "Sum : " << Sum::num << "/" << Sum::den << std::endl; std::cout << "Product : " << Product::num << "/" << Product::den << std::endl;Output:
Sum : 5/6 Product : 1/6
For more details see ratio - at CppReference.com
The class ratio can be used within chrono library to define the time unit as a fraction of seconds.
#include <thread> #include <chrono> // wait for a duration of 100 ms std::this_thread::sleep_for(std::chrono::milliseconds(100));
// Calculate a timepoint 5 seconds in the future auto timepoint = std::chrono::system_clock::now() + std::chrono::seconds(5); // do something which needs some time // wait the rest of the remaining 5 seconds std::this_thread::sleep_until(timepoint);
// Calculated duration is of type chrono::seconds auto duration = std::chrono::hours(1) + std::chrono::minutes(2) + std::chrono::seconds(10); std::cout << "Calculated duration [sec]: " << duration.count() << std::endl; // Work day of 10 hours std::chrono::hours myWorkDay(10); std::cout << "Work day [h]: " << myWorkDay.count() << std::endl; // Remaining work time in minutes auto remainingWorkTime = myWorkDay - std::chrono::minutes(5); std::cout << "Remaining work time [min]: " << remainingWorkTime.count() << std::endl;Output:
Calculated duration [sec]: 3730 Work day [h]: 10 Remaining work time [min]: 595
// Construct a date time_t MakeDate ( int in_day, // 1, 2, ..., 31 int in_month, // 1, 2, ..., 12 int in_year) // 1900, 1901, ... { std::tm timeinfo = std::tm(); timeinfo.tm_mday = in_day; timeinfo.tm_mon = in_month-1; // zero based index timeinfo.tm_year = in_year - 1900; std::time_t date = std::mktime (&timeinfo); return date; }
// Generate standard format for date/time using predefined format functions // Possible result: "Tue Dec 31 11:47:13 2013" std::string TimePoint2String ( std::chrono::system_clock::time_point & in_timePoint) { time_t t = std::chrono::system_clock::to_time_t(in_timePoint); char buffer [50]; ctime_s(buffer,50,&t); // generate standard format std::string retVal = buffer; retVal.resize(retVal.size()-1); // remove line break return retVal; }
// Generate custom date format // Possible reults: "30.12.13", "30.12.2013", // "Monday, 30.12.13", "30.12.13 23:59:59" enum class WriteDate {NO, SIMPLE, WEEKDAY, CENTURY, WEEKDAY_CENTURY}; enum class WriteTime {NO, SIMPLE, SECOND}; std::string FormatAsDate ( std::chrono::system_clock::time_point & in_timePoint, WriteDate in_writeDate = WriteDate::SIMPLE, WriteTime in_writeTime = WriteTime::NO) { const char* weekDay[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; time_t rawtime = std::chrono::system_clock::to_time_t(in_timePoint); struct tm timeinfo; localtime_s (&timeinfo, &rawtime ); std::ostringstream oss; if ( (in_writeDate == WriteDate::WEEKDAY) || (in_writeDate == WriteDate::WEEKDAY_CENTURY)) { oss << weekDay[timeinfo.tm_wday] << ", "; } oss << std::setfill('0') << std::setw(2) << timeinfo.tm_mday << "." << std::setfill('0') << std::setw(2) << timeinfo.tm_mon + 1 << "."; if ( (in_writeDate == WriteDate::CENTURY) || (in_writeDate == WriteDate::WEEKDAY_CENTURY)) { oss << timeinfo.tm_year + 1900; } else { oss << timeinfo.tm_year % 100; } if ((in_writeDate != WriteDate::NO) && (in_writeTime != WriteTime::NO)) { oss << " "; } if (in_writeTime != WriteTime::NO) { oss << std::setfill('0') << std::setw(2) << timeinfo.tm_hour << ":" << std::setfill('0') << std::setw(2)<< timeinfo.tm_min; if (in_writeTime == WriteTime::SECOND) { oss << ":" << std::setfill('0') << std::setw(2) << timeinfo.tm_sec; } } return oss.str(); }
std::chrono supports calculation of timepoints and time durations. To get the real calendar date which is represented by a timepoint you have to convert to date format time_t with use of std::chrono::system_clock::to_time_t.
#include <ctime> #include <sstream> #include <iomanip> #include <vector> using namespace std::chrono; // Hint: For the conversion of timepoint to type time_t // see helper funtions TimePoint2String and FormatAsDate system_clock::time_point today = system_clock::now(); // add one day and some additional time system_clock::time_point tomorrow = today + std::chrono::hours(25) + std::chrono::minutes(5); // days is not predefined, so define it by yourself, // unit of ratio is seconds typedef std::chrono::duration<long,std::ratio<24*3600,1>> days; system_clock::time_point threeDaysLater = today + days(3); std::cout << "nStandard format:" << std::endl; std::cout << "Today is " << TimePoint2String(today) << std::endl; std::cout << "Tomorrow is " << TimePoint2String(tomorrow) << std::endl; std::cout << "nCustom format:" << std::endl; std::cout << "Today is " << FormatAsDate(today, WriteDate::WEEKDAY_CENTURY, WriteTime::SIMPLE) << std::endl; std::cout << "Tomorrow is " << FormatAsDate(tomorrow, WriteDate::WEEKDAY_CENTURY, WriteTime::SIMPLE) << std::endl; std::cout << "nCustom format simplified:" << std::endl; std::cout << "Today is " << FormatAsDate(today) << std::endl; std::cout << "3 days later is " << FormatAsDate(threeDaysLater) << std::endl;Output:
Standard format: Today is Tue Dec 31 11:47:13 2013 Tomorrow is Wed Jan 01 12:52:13 2014 Custom format: Today is Tuesday, 31.12.2013 11:47 Tomorrow is Wednesday, 01.01.2014 12:52 Custom format simplified: Today is 31.12.13 3 days later is 03.01.14
std::cout << "n2012 is a leap year" << std::endl; system_clock::time_point tpBeforeLeapDay = system_clock:: from_time_t (MakeDate(28,2,2012)); system_clock::time_point tpLeapDay = tpBeforeLeapDay + std::chrono::hours(24); std::cout << "Before leap day: " << FormatAsDate(tpBeforeLeapDay) << std::endl; std::cout << "Leap day : " << FormatAsDate(tpLeapDay) << std::endl; std::cout << "n2013 is not a leap year" << std::endl; system_clock::time_point tpFirstMarch = system_clock:: from_time_t (MakeDate(1,3,2013)); system_clock::time_point tpOneSecBefore = tpFirstMarch - std::chrono::seconds(1); std::cout << "First day in march: " << FormatAsDate(tpFirstMarch, WriteDate::SIMPLE,WriteTime::SECOND) << std::endl; std::cout << "One second before : " << FormatAsDate(tpOneSecBefore, WriteDate::SIMPLE,WriteTime::SECOND) << std::endl;Output:
2012 is a leap year Before leap day: 28.02.12 Leap day : 29.02.12 2013 is not a leap year First day in march: 01.03.13 00:00:00 One second before : 28.02.13 23:59:59
The following code requests the properties for the system_clock:
// default contructor of time_point represents epoch of clock // local time is considered! std::chrono::system_clock::time_point epoch; // Time period is given in fraction of seconds // Now converting to fraction of milli seconds double precisionMs = system_clock::period::num * 1000.0 / system_clock::period::den; std::cout << "nInfo about system_clock" << std::endl; std::cout << "epoch : " << FormatAsDate(epoch, WriteDate::CENTURY,WriteTime::SIMPLE) << std::endl; std::cout << "precision : " << std::fixed << precisionMs << " ms" << std::endl; std::cout << "steady : " << std::boolalpha << system_clock::is_steady << std::endl;Output:
Info about system_clock epoch : 01.01.1970 01:00 precision : 0.000100 ms steady : false
For more details see system_clock - usage info at CppReference.com
To access e.g. the second element within your tuple you can use std::get<1>(yourTuple). But as the access is through template functionality the used index has to be a compile time constant!
Using std::tuple_cat you can concatenate several tuples to one big tuple.
For more details see tuple - usage info at CppReference.com
// Define and init tuple explicitly std::tuple<std::string,int,double> someTuple("ABC", 42, 3.14); // Change some entries // Restriction: used index must be a constant! std::get<0>(someTuple) = "SomeTuple"; std::get<1>(someTuple)++; std::get<2>(someTuple) -= 2; // Write to stdout using template helper function WriteTuple(someTuple); // Create a tuple without explicit definition auto otherTuple = std::make_tuple("OtherTuple", 2.987, 12, 56, true); WriteTuple(otherTuple);Output:
(SomeTuple / 43 / 1.14) (OtherTuple / 2.99 / 12 / 56 / true)
// There are some variables int valA = 2; int valB = 4; // Create a tuple with references auto refTuple = std::make_tuple("RefTuple", std::cref(valA), std::ref(valB)); // Change values valA = 222; // Change valB through tuple reference std::get<2>(refTuple) += 5; // Remark: "std::get<1>(refTuple)++;" is not // possible because of const ref WriteTuple(refTuple); std::cout << "valA=" << valA << std::endl; std::cout << "valB=" << valB << std::endl; // Create tuple of (non const) references auto refTuple2 = std::tie(valA, valB); std::get<0>(refTuple2) = -2; std::get<1>(refTuple2) = -4; WriteTuple(refTuple2); std::cout << "valA=" << valA << std::endl; std::cout << "valB=" << valB << std::endl;Output:
(RefTuple / 222 / 9) valA=222 valB=9 (-2 / -4) valA=-2 valB=-4
auto tuple = std::make_tuple("AnyTuple",3.14, 4711, true); // Extract selected elements of a tuple double pi=0; int num=0; std::tie(std::ignore, pi, num, std::ignore) = tuple; // Remark: The returned value of std::tie // is also a tuple which is not used here std::cout << "pi=" << pi << std::endl; std::cout << "num=" << num << std::endl;Output:
pi=3.14 num=4711
// Generic mechanismm to write a tuple to std out. // Tuple can be of any length and may contain arbitrary types. // Required: all types need to be streamable. // Define a type for each unsigned integer value // The type represents the index of the tuple element template<std::size_t> struct Int2Type{}; // Write tuple element at index IDX template <class TUPLE, size_t IDX> std::ostream& WriteTupleElement(std::ostream& out, const TUPLE& t, Int2Type<IDX> ) { // Write element at position IDX // we also know that there is at least one element following // otherwise the specialized template would have been used out << std::get< IDX >(t) << " / "; // Recursive call to write next element return WriteTupleElement(out, t, Int2Type<IDX+1>()); } // Specialization for last element, i.e. idx is size of tuple -1 template <class TUPLE> std::ostream& WriteTupleElement(std::ostream& out, const TUPLE& t, Int2Type<std::tuple_size<TUPLE>::value-1> ) { return out << std::get<std::tuple_size<TUPLE>::value-1>(t); } // Template function to be callled by client code template<typename TUPLE> void WriteTuple(TUPLE t) { // Choose format for all elements std::cout << std::fixed << std::setprecision(2) << "("; // Recursive call for all elements WriteTupleElement(std::cout, t, Int2Type<0>()); // Add new line after last element std::cout << ")" << std::endl; }
Always use a standard array
For more details see arrray - usage info at CppReference.com
#include <array> const int MY_ARRAY_SIZE = 5; typedef std::array<int, MY_ARRAY_SIZE> MyArrayType;Create and use array:
// Fully and explicitly initialized array MyArrayType myArray = {1,2,3,4,5}; // Access array elements myArray[0] = 4; myArray.at(2) +=3;
// Uninitialized array, // each element may have an arbitrary value MyArrayType myArray1; // Partly initialized array // values: 1,2,3,0,0 MyArrayType myArray2 = {1,2,3}; // Zero initialized array // values: 0,0,0,0,0 MyArrayType myArray3 = {};
For more details see forward_list - usage info at CppReference.com
#include <forward_list> typedef std::forward_list<int> MyListType;Create and use forward_list:
// Define empty list MyListType myList; // Fill list (values: 1,2,5) myList.push_front(5); myList.push_front(2); myList.push_front(1); // Insert missing values 3 and 4 after value 2 // values: 1,2,3,4,5 auto itPos2 = std::find(myList.begin(),myList.end(),2); auto itPos3 = myList.insert_after(itPos2,3); auto itPos4 = myList.insert_after(itPos3,4); // Remove the following element // values: 1,2,3,4 myList.erase_after(itPos4); // Remove first element // values: 2,3,4 myList.pop_front(); // Access the remaining first element (=2) int num = myList.front();
In addition there are a number of other new algorithms, which will be only listed here. For more information please klick on the external links:
For more details see usage info at CppReference.com
#include <algorithm> ... std::vectormyNumbers; myNumbers.push_back(2); myNumbers.push_back(3); bool anyNumGreater3 = std::any_of( myNumbers.begin(),myNumbers.end(), greater3); // anyNumGreater3: false myNumbers.push_back(4); anyNumGreater3 = std::any_of( myNumbers.begin(),myNumbers.end(), greater3); // anyNumGreater3: true // chek range via lambda function bool allNumWithinRange = std::all_of( myNumbers.begin(),myNumbers.end(), [](int i) {return i>1 && i<4;}); // allNumWithinRange: false // check bool noneIsNegative = std::none_of ( myNumbers.begin(),myNumbers.end(), [](int i) {return i<0;}); // noneIsNegative: true
// Construct list of 5 integers (with value 0) std::list<int> myList(5); // Set list values to 5,6,7,8,9 std::iota(myList.begin(),myList.end(),5); // Create vector with same size as the list std::vector<int> myVec(myList.size()); // Transfer the list elements to the vector std::iota(myVec.begin(),myVec.end(),myList.begin());For more details see usage info at CppReference.com
Depending on your needs choose one of the following smart pointer types:
struct BigData { BigData (std::string const & in_data) : m_data (in_data) { std::cout << "BigData-Constructor " << in_data << std::endl; } ~BigData () { std::cout << "BigData-Destructor" << std::endl; } // possibly a very long string std::string m_data; }; typedef std::unique_ptrThis expensive data struct is contained within some class:BigDataUp;
struct SomeObject { // default constructor SomeObject() {std::cout << "SomeObject-DefaultConstructor" << std::endl;} // constructor with argument SomeObject(std::string const & in_data) : m_upBigData (new BigData(in_data)) {std::cout << "SomeObject-Constructor" << std::endl;} // copy constructor SomeObject (SomeObject const& rhs) { std::cout << "SomeObject-CopyConstructor" << std::endl; if (rhs.m_upBigData) { // Copy big data m_upBigData.reset(new BigData(rhs.m_upBigData->m_data)); } } // assignment operator SomeObject& operator= (SomeObject const& rhs) { std::cout << "SomeObject-AssignmentOp" << std::endl; if (this != &rhs) { m_upBigData.reset(); // delete old contents if (rhs.m_upBigData) { // Deep copy of big data m_upBigData.reset(new BigData(rhs.m_upBigData->m_data)); } } return *this; } // Unique ptr to big data stored on heap BigDataUp m_upBigData; };Client code creating copies from SomeObject:
{ std::cout << "nAssignment from temporary object" << std::endl; SomeObject a; a = SomeObject("XYZ"); } { std::cout << "nAssignment from regular object" << std::endl; SomeObject a("ABCDEF"); SomeObject b; b = a; }Result: Big data has to be created always twice:
Assignment from temporary object SomeObject-DefaultConstructor BigData-Constructor XYZ SomeObject-Constructor SomeObject-AssignmentOp BigData-Constructor XYZ BigData-Destructor BigData-Destructor Assignment from regular object BigData-Constructor ABCDEF SomeObject-Constructor SomeObject-DefaultConstructor SomeObject-AssignmentOp BigData-Constructor ABCDEF BigData-Destructor BigData-Destructor
struct SomeObject { ... // move copy constructor SomeObject(SomeObject && rhs) : m_upBigData (std::move(rhs.m_upBigData)) { std::cout << "SomeObject-MoveCopyConstructor" << std::endl; } // move assignment operator SomeObject& operator= (SomeObject&& rhs) { std::cout << "SomeObject-MoveAssignmentOp" << std::endl; if (this != &rhs) { m_upBigData.reset(); // transfer ownership of big data m_upBigData = std::move(rhs.m_upBigData); } return *this; } }The client code has to be slightly modified:
{ std::cout << "nMove assignment operator implicitly called" << std::endl; SomeObject a; a = SomeObject("XYZ"); // temporary object is an rvalue } { std::cout << "nMove assignment operator explicitly called" << std::endl; SomeObject a("ABCDEF"); SomeObject b; // std::move converts to rvalue thus allowing use of move assignment op b = std::move(a); // from here on "a" has lost its data! // contents were moved to "b" }The you can observe that big data will only be created once for each case:
Move assignment operator implicitly called SomeObject-DefaultConstructor BigData-Constructor XYZ SomeObject-Constructor SomeObject-MoveAssignmentOp BigData-Destructor Move assignment operator explicitly called BigData-Constructor ABCDEF SomeObject-Constructor SomeObject-DefaultConstructor SomeObject-MoveAssignmentOp BigData-Destructor RValueReferences-End
int a; int b; // a and b are lvalues a = b; b = a; // a*b is an rvalue a = a*b; a*b = 42; // compile error! int& MyFuncA(); int MyFuncB(); // MyFuncA is an lvalue int c = MyFuncA MyFuncA() = 42; // OK! int* pInt = &MyFuncA(); // OK! // MyFuncB is an rvalue int d = MyFuncB(); MyFuncB() = 17; // compile error! int* pInt2 = &MyFunccB(); // compile error!
New syntax for rvalue params:
void SomeFunction(X&& in_x);In most cases the relevant rvalue functions are copy constructors and asignment operators.
With SomeFunction(std::move(x)) the programmer simply says to the compiler: regard x as an rvalue and try to use the optimized overload if it is available.
A simple approach for the waiting thread might be "polling": he repeatedly checks some shared data until he recognizes that the data's state allows to start his own processing. If the state is not yet reached he sleeps for a small time interval and then repeats the check.
The typical disadvantages of this approach are: