diff options
Diffstat (limited to 'c++.html.markdown')
| -rw-r--r-- | c++.html.markdown | 138 | 
1 files changed, 110 insertions, 28 deletions
| diff --git a/c++.html.markdown b/c++.html.markdown index ff2a98fd..4acc1b9d 100644 --- a/c++.html.markdown +++ b/c++.html.markdown @@ -4,6 +4,8 @@ filename: learncpp.cpp  contributors:      - ["Steven Basart", "http://github.com/xksteven"]      - ["Matt Kline", "https://github.com/mrkline"] +    - ["Geoff Liu", "http://geoffliu.me"] +    - ["Connor Waters", "http://github.com/connorwaters"]  lang: en  --- @@ -52,11 +54,11 @@ int main(int argc, char** argv)  // However, C++ varies in some of the following ways: -// In C++, character literals are one byte. -sizeof('c') == 1 +// In C++, character literals are chars +sizeof('c') == sizeof(char) == 1 -// In C, character literals are the same size as ints. -sizeof('c') == sizeof(10) +// In C, character literals are ints +sizeof('c') == sizeof(int)  // C++ has strict prototyping @@ -158,11 +160,12 @@ void foo()  int main()  { -    // Assume everything is from the namespace "Second" -    // unless otherwise specified. +    // Includes all symbols from namespace Second into the current scope. Note +    // that simply foo() no longer works, since it is now ambiguous whether +    // we're calling the foo in namespace Second or the top level.      using namespace Second; -    foo(); // prints "This is Second::foo" +    Second::foo(); // prints "This is Second::foo"      First::Nested::foo(); // prints "This is First::Nested::foo"      ::foo(); // prints "This is global foo"  } @@ -248,6 +251,59 @@ const string& barRef = bar; // Create a const reference to bar.  // Like C, const values (and pointers and references) cannot be modified.  barRef += ". Hi!"; // Error, const references cannot be modified. +// Sidetrack: Before we talk more about references, we must introduce a concept +// called a temporary object. Suppose we have the following code: +string tempObjectFun() { ... } +string retVal = tempObjectFun(); + +// What happens in the second line is actually: +//   - a string object is returned from tempObjectFun +//   - a new string is constructed with the returned object as arugment to the +//     constructor +//   - the returned object is destroyed +// The returned object is called a temporary object. Temporary objects are +// created whenever a function returns an object, and they are destroyed at the +// end of the evaluation of the enclosing expression (Well, this is what the +// standard says, but compilers are allowed to change this behavior. Look up +// "return value optimization" if you're into this kind of details). So in this +// code: +foo(bar(tempObjectFun())) + +// assuming foo and bar exist, the object returned from tempObjectFun is +// passed to bar, and it is destroyed before foo is called. + +// Now back to references. The exception to the "at the end of the enclosing +// expression" rule is if a temporary object is bound to a const reference, in +// which case its life gets extended to the current scope: + +void constReferenceTempObjectFun() { +  // constRef gets the temporary object, and it is valid until the end of this +  // function. +  const string& constRef = tempObjectFun(); +  ... +} + +// Another kind of reference introduced in C++11 is specifically for temporary +// objects. You cannot have a variable of its type, but it takes precedence in +// overload resolution: + +void someFun(string& s) { ... }  // Regular reference +void someFun(string&& s) { ... }  // Reference to temporary object + +string foo; +someFun(foo);  // Calls the version with regular reference +someFun(tempObjectFun());  // Calls the version with temporary reference + +// For example, you will see these two versions of constructors for +// std::basic_string: +basic_string(const basic_string& other); +basic_string(basic_string&& other); + +// Idea being if we are constructing a new string from a temporary object (which +// is going to be destroyed soon anyway), we can have a more efficient +// constructor that "salvages" parts of that temporary string. You will see this +// concept referred to as "move semantics". +  //////////////////////////////////////////  // Classes and object-oriented programming  ////////////////////////////////////////// @@ -294,7 +350,10 @@ public:      // These are called when an object is deleted or falls out of scope.      // This enables powerful paradigms such as RAII      // (see below) -    // Destructors must be virtual to allow classes to be derived from this one. +    // The destructor should be virtual if a class is to be derived from; +    // if it is not virtual, then the derived class' destructor will +    // not be called if the object is destroyed through a base-class reference +    // or pointer.      virtual ~Dog();  }; // A semicolon must follow the class definition. @@ -437,9 +496,10 @@ int main () {  /////////////////////  // Templates in C++ are mostly used for generic programming, though they are -// much more powerful than generics constructs in other languages. It also -// supports explicit and partial specialization, functional-style type classes, -// and also it's Turing-complete. +// much more powerful than generic constructs in other languages. They also +// support explicit and partial specialization and functional-style type +// classes; in fact, they are a Turing-complete functional language embedded +// in C++!  // We start with the kind of generic programming you might be familiar with. To  // define a class or function that takes a type parameter: @@ -451,7 +511,7 @@ public:  };  // During compilation, the compiler actually generates copies of each template -// with parameters substituted, and so the full definition of the class must be +// with parameters substituted, so the full definition of the class must be  // present at each invocation. This is why you will see template classes defined  // entirely in header files. @@ -465,13 +525,13 @@ intBox.insert(123);  Box<Box<int> > boxOfBox;  boxOfBox.insert(intBox); -// Up until C++11, you must place a space between the two '>'s, otherwise '>>' -// will be parsed as the right shift operator. +// Until C++11, you had to place a space between the two '>'s, otherwise '>>' +// would be parsed as the right shift operator.  // You will sometimes see  //   template<typename T> -// instead. The 'class' keyword and 'typename' keyword are _mostly_ -// interchangeable in this case. For full explanation, see +// instead. The 'class' keyword and 'typename' keywords are _mostly_ +// interchangeable in this case. For the full explanation, see  //   http://en.wikipedia.org/wiki/Typename  // (yes, that keyword has its own Wikipedia page). @@ -527,12 +587,15 @@ try {      // Do not allocate exceptions on the heap using _new_.      throw std::runtime_error("A problem occurred");  } +  // Catch exceptions by const reference if they are objects  catch (const std::exception& ex)  { -  std::cout << ex.what(); +    std::cout << ex.what(); +} +  // Catches any exception not caught by previous _catch_ blocks -} catch (...) +catch (...)  {      std::cout << "Unknown exception caught";      throw; // Re-throws the exception @@ -542,8 +605,8 @@ catch (const std::exception& ex)  // RAII  /////// -// RAII stands for Resource Allocation Is Initialization. -// It is often considered the most powerful paradigm in C++, +// RAII stands for "Resource Acquisition Is Initialization". +// It is often considered the most powerful paradigm in C++  // and is the simple concept that a constructor for an object  // acquires that object's resources and the destructor releases them. @@ -564,9 +627,9 @@ void doSomethingWithAFile(const char* filename)  // Unfortunately, things are quickly complicated by error handling.  // Suppose fopen can fail, and that doSomethingWithTheFile and  // doSomethingElseWithIt return error codes if they fail. -// (Exceptions are the preferred way of handling failure, -//  but some programmers, especially those with a C background, -//  disagree on the utility of exceptions). +//  (Exceptions are the preferred way of handling failure, +//   but some programmers, especially those with a C background, +//   disagree on the utility of exceptions).  // We now have to check each call for failure and close the file handle  // if a problem occurred.  bool doSomethingWithAFile(const char* filename) @@ -680,26 +743,29 @@ class Foo {    virtual void bar();  };  class FooSub : public Foo { -  virtual void bar();  // overrides Foo::bar! +  virtual void bar();  // Overrides Foo::bar!  };  // 0 == false == NULL (most of the time)!  bool* pt = new bool; -*pt = 0;  // Sets the value points by 'pt' to false. +*pt = 0; // Sets the value points by 'pt' to false.  pt = 0;  // Sets 'pt' to the null pointer. Both lines compile without warnings.  // nullptr is supposed to fix some of that issue:  int* pt2 = new int; -*pt2 = nullptr;  // Doesn't compile +*pt2 = nullptr; // Doesn't compile  pt2 = nullptr;  // Sets pt2 to null. -// But somehow 'bool' type is an exception (this is to make `if (ptr)` compile). +// There is an exception made for bools. +// This is to allow you to test for null pointers with if(!ptr), +// but as a consequence you can assign nullptr to a bool directly!  *pt = nullptr;  // This still compiles, even though '*pt' is a bool!  // '=' != '=' != '='! -// Calls Foo::Foo(const Foo&) or some variant copy constructor. +// Calls Foo::Foo(const Foo&) or some variant (see move semantics) copy +// constructor.  Foo f2;  Foo f1 = f2; @@ -713,6 +779,22 @@ Foo f1 = fooSub;  Foo f1;  f1 = f2; + +// How to truly clear a container: +class Foo { ... }; +vector<Foo> v; +for (int i = 0; i < 10; ++i) +  v.push_back(Foo()); + +// Following line sets size of v to 0, but destructors don't get called +// and resources aren't released! +v.empty(); +v.push_back(Foo());  // New value is copied into the first Foo we inserted + +// Truly destroys all values in v. See section about temporary objects for +// explanation of why this works. +v.swap(vector<Foo>()); +  ```  Further Reading: | 
