【总结】【C++11】与legacy C对比

Reference:

https://www.stroustrup.com/C++11FAQ.html

Contents

nullptr keyword. Shall be used.

+ Can't be used as an integral value (more typesafe than older ways)
const char *p = nullptr;

enum classes. Shall be used.

+ Enum classes doesn't implicitly convert to int, avoiding errors caused when someone does not want an enumeration to act as an integer. 
+ Enum classes doesn't export their enumerators to the surrounding scope, avoiding name clashes.  
+ Enum classes underlying type can be specified. 
+ Enum classes can be forward declared 
// Example taking from Bjarne explaining enum classes
enum Alert { green, yellow, orange, red }; // traditional enum

enum class Color { red, blue };   // scoped and strongly typed enum
                                  // no export of enumerator names into enclosing scope
                                  // no implicit conversion to int
enum class TrafficLight { red, yellow, green };

Alert a = 7;              // error (as ever in C++)
Color c = 7;              // error: no int->Color conversion

int a2 = red;             // ok: Alert->int conversion
int a3 = Alert::red;      // error in C++98; ok in C++11
int a4 = blue;            // error: blue not in scope
int a5 = Color::blue;     // error: not Color->int conversion

Color a6 = Color::blue;   // ok

Deleting special member functions Shall be used.

+ Keyword ' = delete' disables the use of: Default constructor, Destructor, Copy constructor, Copy assignment operator=, move Constructor or Move operator=
Example of usage:
* remove default constructor when class must be initialized by parameters during construction (for clarity & safety of change).
* prevent copying and assignment of "non copyable" classes.
class C
{
  C() = deleted;
  C(const C&) = deleted;
  C &operator=( const C&) = deleted;
};

See similar topic: Defaulted special member functions

Override controls Shall be used.

+ Keyword override allows compiler to check if there's an appropriate virtual method to override. Previously changing a virtual method signature silently broke all overrides
+ Keyword final prevents further overriding of virtual methods or inheriting of classes
// See Bjarne explain override and final

class Base
{
public:
  virtual void MyMethod ();
};

class MyClass : public Base
{
public:
  // override means compiler will generate compiler error if 
  // there's no Base::MyMethod with matching signature
  void MyMethod () override;
};

class MyOther Class : public Base
{
public:
  // final prevents further overrides of MyMethod
  void MyMethod () final;
};

// final prevents DoNotInheritMe from being inherited
class DoNotInheritMe final
{
};

Smart pointers. Shall be used.

+ Robust life-time management of heap objects (ie new:ed objects)
+ Supports reference counting
+ Supports weak pointers (useful for object graphs)
+ Doesn't require any special base-class for shared objects
+ std::make_shared only does one heap allocation (weak reference counting typically requires two heap allocations)
+ Can create std::shared_ptr from this using std::enable_shared_from_this
+ Deprecates std::auto_ptr (std::auto_ptr was useful but odd)
// See Bjarne explain:
//  1. shared pointers
//  2. weak pointers
//  3. unique pointers

class MyClass
{
  std::shared_ptr<std::string> m_shared;
public:

  MyClass (const std::shared_ptr<std::string> & shared)
   : m_shared (shared)
  { }

  void DoStuff ();
};

auto shared_string = std::make_shared<std::string> ("A shared string");
auto shared_class  = std::make_shared<MyClass> (shared_string);

shared_string.reset ();  // Clears this pointer but since string is referenced
                         // by MyClass instance it's not deleted

if (shared_class)        // Test for non-empty pointers
  shared_class->DoStuff ();

shared_class.reset ();   // Clears this pointer which deletes the MyClass instance
                         // this implicitly clears m_shared which deletes the string value

Auto, typeless declaration. Know about this

  • Use a variable name that tell what the instance is (if it is known in the context).
  • Use auto only if eclipes can deduce the type. It shall be possible to be 100% sure of the type. This unfortuatly removes complicated auto usage.
+ reduces the dependency towards the declared types and allows for typechange without code modification.
+ removes extensive typedeclarations that clutter the code and take focus from what the code really does.
- hides the type of the variable. Example: if it is changable (const or not).
- forces usage "advanced" tools (eclipse, ...) to know the type.
- require disabling of alot of lint checks 

The lint errors wary depending on how the variable is used, Example:

/*lint -e808 -e64 -e55 -e58 -e48 -e10 -e118 -e1013 -e40 -e1055 -e746 */
  • How and when to us auto depends on circumstances, see Examples and Guidelines for other c++11 features.

 

Uniform initialization Know about this

Automatically deduce type of object to construct
+ Remove the need for redundant typename/constructor.

At return:

Point DoubleHeight() {
 return { x, y, z*2 };  // old style needs a specific constructor 'return Point(x, y, z*2 );'
}
 return {};  // return a empty list regardless of type

At object list-initialization:

std::vector<Point> listOfMirrorOnPlanes {{ x, y, 0 }, [x, 0, z}, {0, y, z}};

In functions arguments

float distance(Point p);
.......
auto length = distance( { x, y, z } );

Range Based For Loops Know about this

Prefered usage:

for (const auto& instance : container) { instace.function(); }

const to ensute that nothing changes (sequrity)
auto to allow remove dependency of type (allow change of design)
& to avoid copy of instance (efficiency)
//lint ....

const iterators Know about this

  • cbegin
  • cend
+ Use const type while iterating to sequre against modification.
- Requires disabling a lot of lint rules
 /*lint -e1013 -e1055 -e48 -e10 -e40 -e118 (C++11)*/
 for (auto connection = m_connectionMapT.cbegin(); connection != m_connectionMapT.cend(); ++connection)
 {
   if( connection->second.getRemoteConnectionRef() == remoteConnectionRef && connection->second.getRemotePid() == remotePid )
   {
     localConnectionRef = connection->first;
     return true;
   }
 }
 return false;

initializer lists Know about this

+ Easy initialization (very useful for data driven tests)
- lint warnings
//lint !e64 (C++11)
// See Bjarne explain initializer lists
std::vector<U32> procedureRefIdentifiers = {RBS_IW_CGCI_CONN_ESTABLISH_REQ};//lint !e64  !e838 (C++11)

// Initializing test data for PM
// pmMoClassCounterDefinitions_t is a vector of ClassCounterDefinitions
const pmMoClassCounterDefinitions_t standardClassCounterDefinitions =
{
  {
    MoClassId_1                                       , // moClassId
    MOCLASSNAME_1                                     , // moClassName
    MaxNoOfInstances_MOC1                             , // maxNoOfMoInstances
    // Initializes a vector of counter definitions
    {
      {
        CounterId_1                                   , // counterId
        COUNTERNAME_1                                 , // counterName
        PmCollectionMethod::CC                        , // collectionMethod
        PmCounterAggregationMethod::Sum               , // counterAggregationMethod
        false                                         , // compressedFormatSupported
        PmCounterSize::_64Bit                         , // counterSize
        true                                          , // resetCounterAtEOR
        10                                            , // initialValue
        1                                             , // multiplicity
      },
  },
}

Lambda expressions Know about this

+ Simplifies use of C++ algorithms (<algorithm>)
+ Supports capture of values and references
+ Mostly deprecates the need for functional objects
+ Enables functional-style programming
- Syntax can feel odd in the beginning
// See Bjarne explain lambda expressions
// Basically lambda expressions allows a developer to define an inline function

std::vector<int> data = get_data ();

auto find_5  = std::find_if (
                 data.begin () , 
                 data.end ()   , 
                 // An inline function that takes an int
                 //  returns true if input is equal to 5
                 [] (int i) 
                 {
                   return i == 5;
                 }             );

auto x       = 3;
auto find_x  = std::find_if (
                 data.begin () , 
                 data.end ()   , 
                 // An inline function that takes an int
                 //  returns true if input is equal to x
                 //  as x needs to be captured we have to list
                 //  x is in the capture list ([x])
                 [x] (int i) 
                 {
                   return i == x;
                 }             );

// Lambdas can be handled as values (functional style)
auto test_x2 = [x] (int i) {return i == x;};
auto otest_x2= test_x2;
auto find_x2 = std::find_if (data.begin (), data.end () , test_x2);

// Lambdas can also be stored as std::function<>, useful
//  if you want to save the lambda as member or return from function
std::function<bool (int i)> test_x3 = [x] (int i) {return i == x;};

// Note; the C++ compiler can't optimize this as heavily since 
//  std::function relies on virtual dispatch which hides information
//  from the compiler
auto find_x3 = std::find_if (data.begin (), data.end () , test_x3);

return test_x3;

Raw string literals Know about this

+ Simplifies writing strings with embedded whitespace characters (\n,\r ...)
+ Flexible prelude and epilogue makes it possible to avoid escaping
// See Bjarne explain raw string literals

// Without raw string literals:
auto some_regex    = "('(?:[^\\\\']|\\\\.)*'|\"(?:[^\\\\\"]|\\\\.)*\")|";
auto quoted_string = "\"quoted string\"";

// With raw string literals (note the R):
auto rquoted_string= R"("quoted string")";

// Prints: "quoted string"
printf ("%s\n", rquoted_string)

Control of defaults Know about this Shall be used 

+ Keyword default allows creation of default implementation of ctors/assignment operators
+ Keyword delete allows creation of default implementation of ctors/assignment operators
+ Keyword delete allows creation of deleted methods (used to prevent errornous overloads)
// See Bjarne explain default and delete

class MyDefaultConstructibleClass
{
public:
 // This supresses the default constructor
 MyDefaultConstructibleClass (int i);

 // Use default to unsupress it
 MyDefaultConstructibleClass ()        = default;
};

class MyNonCopyableClass
{
public:
 // Prevents default copy
 MyNonCopyableClass (const MyNonCopyableClass&)            = delete;
 MyNonCopyableClass& operator= (const MyNonCopyableClass&) = delete;
};

class MyMoveableClass
{
public:
 // Support default move (also implicitly prevents copying)
 MyMoveableClass (MyMoveableClass&&)                       = default;
 MyMoveableClass& operator= (MyMoveableClass&&)            = default;
};

class MyClass
{
public:
 // Support default move & copy
 MyClass (const MyClass&)                                  = default;
 MyClass& operator= (const MyClass&)                       = default;
 MyClass (MyClass&&)                                       = default;
 MyClass& operator= (MyClass&&)                            = default;
};

// A template method that does something
template<typename T>
void MyMethod (T v);

// Deleted methods to prevent calling MyMethod with C-strings
//  Will be part of overload resolution and generate compiler errors
void MyMethod (const char *)   = delete;
void MyMethod (const wchar_t *)= delete;

Static assert Know about this

+ Compile-time asserts
+ Useful for checking invariants that are known during compile-time such as sizeof (4 == sizeof (int)
// See Bjarne explain asserts
static_assert (sizeof (int)  == 4, "ints must be 4 bytes wide");
static_assert (sizeof (long) == 4, "longs must be 4 bytes wide");

template<typename T>
void Method (T&& v)
{
  static_assert (std::is_base_of<Base, T>::value, "T must inherit Base");

  // Do stuff
}

RValue references Know about this

+ Allows overloading on "temporary" objects, this allows for optimizations
+ Is easy to benefit from, you gain performance benefits by recompiling code
+ Allows move semantics for performance and objects that can be moved but not copied
+ There are good patterns when implementing classes that should support RValue references
- RValue references are difficult to fully understand
// See Bjarne explain rvalue references
// See Scott explain universal references

std::string x,y,z,w,u; // Initialize x,y,z,w,u with values

// In C++98: Creates 3 unnecessary string copies
// In C++11: Doesn't create unnecessary string copies
// We benefit by just recompiling the code
auto result = x + y + z + w + u;

class MyNamedMutex
{
 std::string m_name;
public:
 MyNamedMutex (std::string name)
   // Moves the content of name into m_name to avoid 
   //  unnecessary copies
   : m_name (std::move (name))
 {
 }

 // A named mutex can't be copied, but they can be moved
 MyNamedMutex (MyNamedMutex &&);
};

MyNamedMutex CreateMutex ();

// Creates a mutex and moves it the calling context
auto mutex = CreateMutex ();

std::vector<int> ReturnsBigData ();

// In C++98: Potentially creates an extra copy of BigData, pray for RVO
// In C++11: Never creates an extra copy of BigData
auto big_data  = ReturnsBigDate ();

 

default member initialization (of non-static members). 

+ derived classes becomes less dependent of base class implementation. 
Note that constructor initializaer list override this (the old way to initialize members).
class C
{
 private:
  int x = 5;
  std::string id = { defaultID() };
};

Templates using c++11 features

...

= links =

 

Index

Comment

Legacy C/C++

C++

1

String handling

const char*

strcmp, strdup, strcpy

std::string

2

 

struct

class

3

Pointers(尽量使用智能指针)

*

malloc, free, memcpy

 

&

std::shared_ptr

std::weak_ptr

std::unique_ptr

4

Arrays(使用STL)

new [] /delete []

std::vector

std::array

5

String formatting

printf, sprintf and similar

std::ostream <<

6

Enumeration(使用enum  class)

enum

enum class

7

Function pointer

C style function pointer.

SLOT

std::function

8

Type casting.

This should be avoided and should rarely be needed.

C style type casting

static_cast, dynamic_cast, const_cast.

9

Allocation of dynamic data. (note, consider using smart pointers for controlling the lifecycle of objects instead). 

malloc, free

new,delete

10

 

typedef

using

11

Looping over a container.

iterators

range-based for loop

12

 

NULL, NIL

nullptr

13

Data initialization

=

{} this gives stronger type check

 

Smart pointers

 

From <https://en.cppreference.com/w/cpp/memory

Smart pointers enable automatic, exception-safe, object lifetime management.

Defined in header <memory>

 

  1. std::shared_ptr

template< class T > class shared_ptr;

 

(since C++11)

 

包含共享得个数和对象

std::shared_ptr is a smart pointer that retains shared ownership of an object through a pointer. Several shared_ptr objects may own the same object. The object is destroyed and its memory deallocated when either of the following happens:

  • the last remaining shared_ptr owning the object is destroyed;
  • the last remaining shared_ptr owning the object is assigned another pointer via operator= or reset().

The object is destroyed using delete-expression or a custom deleter that is supplied to shared_ptr during

Usage of Smart Pointers8.5

Using of smart pointers is encouraged for avoiding problems with controlling the lifecycle of dynamically allocated objects. These rules apply:

  • The raw C pointer shall never be stored from a smart pointer.
  • For callbacks, std::weak_ptr should normally be used to avoid circular pointer references.
  • For objects accessed by one object, std::unique_ptr should be used, otherwise std::shared_ptr should be used.
  • std::auto_ptr is deprecated and shall not be used – std::unique_ptr should be used instead.
  • When creating objects owned by smart pointers, these should preferably be created by std::make_unique resp std::make_shared

In function signatures, the following applies:

  • use a raw reference if the function is just using the pointer and not altering its ownership -- i.e. not storing it/replacing it
  • if the function is consuming the object: use std::unique_ptr by value
  • if the function is taking shared ownership: use std::shared_ptr by value
  • if the function will reseat the pointer (replace it): use std::unique_ptr / std::shared_ptr by reference

For more information on principles for using smart pointers, please read the good rules defined in reference (which contains examples and motivations):

https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rr-owner

 

Enum class/enum struct

  1. 作用域:enum只能用namespace来解决重名问题

https://blog.csdn.net/thinkerleo1997/article/details/80355905

std::function(2.32

 

From <https://blog.csdn.net/acoolgiser/article/details/90705650

 

 

但是采用模板最大的问题在于编译期展开,头文件会变得很大,编译时间也会很长。

C++11引入std::function更好的解决了这一问题。

 

std::function可以用于保存并调用任何可调用的东西,比如函数、lambda函数、std::bind表达式、仿函数,甚至是指向对象成员的指针。

 

std::function简单来说就像是个接口,且能够把符合这个接口的对象(这里对象泛指一切类型,并非面向对象编程中的对象)储存起来,更神奇的是,两个std::function的内容可以交换。

uniform initialization(标准初始化)以及initializer_list(2.14

在c++11中就统一了初始化的形式——“{ }”,直接在对象名后面跟大括号,并在大括号中写入需要初始化的值,并用逗号隔开。甚至类构造函数的初始化列表也可以用“{}”大括号

  1. int values[] {1,2,3,4};
  1. vector<int> v {1,2,3,4};
  1. complex<double> c{3.0,4.0};

Bad example:

int pi = 3.14; // no compilation error, i truncated to 3

Better example:

double pi {3.14}; //compilation error if pi is not float or double

 

initializer_list<>

上面所说的标准初始化格式,并不仅仅是形式上的统一,而是在背后有一个更加复杂的机制。编译器会将大括号里面的内容({1,2,3,4})编译成一个initializer_list<>,我们可以把它理解为一个模板容器(其背后的机制是array,但是我们这里不做探讨)。这时候编译器就会调用形参是initializer_list的函数,或者是构造函数。如果没有找到对应的形式,就会将initializer_list分解为单个的元素,进行匹配。

 

Take advantage of type definitions defined by STL containers:

When using STL containers, avoid duplication in code by creating a type definition for the instantiation of the container template, and using the provided type definitions such as value_type, reference, const_reference, and so forth.

Example:

class MyClass

{

    using FrequencyList = std::vector<Frequency>;

    FrequencyList m_List;

    FrequencyList::const_reference getEntry(…) const;

};

member typedefinitionnotes
value_typeThe first template parameter (T) 
allocator_typeThe second template parameter (Alloc)defaults to: allocator<value_type>
referencevalue_type& 
const_referenceconst value_type& 
pointerallocator_traits<allocator_type>::pointerfor the default allocator: value_type*
const_pointerallocator_traits<allocator_type>::const_pointerfor the default allocator: const value_type*

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值