国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > C++ > 正文

C++ Dos and Don'ts

2019-11-08 19:45:38
字體:
供稿:網(wǎng)友

最小化頭文件

不要包含不必要的頭文件

盡量使用前向聲明的方式,目的是為了減少編譯時間What are forward declarations in C++?,并且在頭文件發(fā)生改變的時候,減少重新編譯的文件。

將內(nèi)部類移動到實現(xiàn)中

// 內(nèi)部類的聲明class Whatever { public: /* ... */ PRivate: struct DataStruct; std::vector<DataStruct> data_;};struct Whatever::DataStruct {};

某些時候你不能這么做,因為某些STL數(shù)據(jù)結(jié)構(gòu),需要在聲明的時候就知道其定義,比如:std::deque

將靜態(tài)實現(xiàn)類放到匿名空間中#include "BigImplementationDetail.h"class PublicInterface { public: /* ... */ private: static BigImplementationDetail detail_;};// 你應(yīng)該將BigImplementationDetail挪到實現(xiàn)文件中,并放置在匿名空間中namespace {BigImplementationDetail g_detail;} // namespace

? 不使用這個接口的人是不需要關(guān)心BigImplementationDetail實現(xiàn)細節(jié)的。使用匿名空間的好處就是可以限制對象的作用域在本文件中。

Why are unnamed namespaces used and what are their benefits?Why is an unnamed namespace used instead of static?

停止頭文件中的內(nèi)聯(lián)

一些get,set之類的簡單操作是可以內(nèi)聯(lián)的,記住在頭文件中進行定義的時候都會隱式進行內(nèi)聯(lián)停止對一些復(fù)雜方法進行內(nèi)聯(lián)class DontDoThis { public: int ComputeSomething() { int sum =0; for (int i = 0; i < limit; ++i) { sum += OtherMethod(i, ... ); } return sum; }};

停止對虛方法進行內(nèi)聯(lián)

? 在大多數(shù)情況不要對一個虛方法進行內(nèi)聯(lián),即使是因為這些方法很短也是不可以的,編譯器必須在運行時根據(jù)虛函數(shù)表和指向的類型做分發(fā),如果內(nèi)聯(lián)了就無法知道指向的類型。

Can virtual functions be inlined?

Are inline virtual functions really a non-sense?

?

停止內(nèi)聯(lián)構(gòu)造和析構(gòu)函數(shù)

? 構(gòu)造函數(shù)和析構(gòu)函數(shù)要比我們想象中的要復(fù)雜,因為編譯器會幫我們插入很多初始化的代碼,因此不要認為構(gòu)造函數(shù)和析構(gòu)函數(shù)中沒寫代碼就可以內(nèi)聯(lián)。

什么情況下可以有構(gòu)造函數(shù)和析構(gòu)函數(shù)

如果你的類只有POD類型的數(shù)據(jù),并且沒有顯示的聲明析構(gòu)函數(shù),那么編譯器也不會生成trivial destructor。

struct Data { Data() : count_one(0), count_two(0) {} // No explicit destructor, thus no implicit destructor either. // The members must all be POD for this trick to work. int count_one; int count_two;};

? 沒有繼承,只有很少一些POD類型,構(gòu)造函數(shù)都是一些trivial的整型操作,所以是可以內(nèi)聯(lián)的。對于抽象類, 并且沒有成員的情況,它是可以安全內(nèi)聯(lián)一個trivial的析構(gòu)函數(shù)

class Interface { public: virtual ~Interface() {} virtual void DoSomething(int parameter) = 0; virtual int GetAValue() = 0; };

? 下面兩個接口,不能進行inline。

class ClaimsToBeAnInterface : public base:RefCounted<ClaimsToBeAnInterface> { public: virtual ~ClaimsToBeAnInterface() { /* But derives from a template! */ }};class HasARealMember { public: virtual void InterfaceMethod() = 0; virtual ~HasARealMember() {} protected: vector<string> some_data_;};

小心你的訪問器

不是所有的訪問器都是輕量級的

class Foo { public: int count() const { return count_; } private: int count_;};

? 上面這個訪問器是trivial的,可以很安全的inline,但是下面這些代碼就不行了,即使它們看起來很像。

struct MyData { vector<GURL> urls_; base::Time last_access_;};class Manager { public: MyData get_data() { return my_data_; } private: MyData my_data_;};

? MyData底層的數(shù)據(jù)拷貝很復(fù)雜,所以不適合inline

在頭文件外可以放什么代碼?

? TODO

靜態(tài)變量

? 動態(tài)初始化函數(shù)作用域內(nèi)的靜態(tài)變量在C++11中是線程安全的,因此base::LazyInstance被廣泛使用,

void foo() { static int OK_COUNT = ComputeTheCount(); // OK now, previously a problem. static int GOOD_COUNT = 42; // C++03 3.6.2 says this is done before dynamic initialization, so probably thread-safe. static constexpr int BETTER_COUNT = 42; // Even better, as this will now likely be inlined at compile time.}

變量初始化

在C++11中有很多方式可以用來初始化一個變量,優(yōu)先遵從下面這些規(guī)則:

對于簡單變量的初始化,以及多個literal value組成一個對象的初始化使用賦值語法int i = 1;std::string s = "Hello";std::pair<bool, double> p = {true, 2.0};std::vector<std::string> v = {"one", "two", "three"};

這里使用=號并不會沒有()效率高,因為這里編譯器不會生成臨時變量進行拷貝,并且確保只有隱式的構(gòu)造函數(shù)被調(diào)用,因此讀者在看到這種調(diào)用方式可以假設(shè)沒有什么復(fù)雜或微妙的事情發(fā)生。

當構(gòu)造函數(shù)要執(zhí)行某些重要邏輯的時候,使用構(gòu)造語法,使用一個顯示的構(gòu)造函數(shù)。MyClass c(1.7, false, "test");std::vector<double> v(500, 0.97); // Creates 500 copies of the provided initializer不屬于上面情況的時候使用C++11的統(tǒng)一初始化語法class C { public: explicit C(bool b) { ... }; ...};class UsesC { ... private: C c{true}; // Cannot use '=' since C() is explicit (and "()" is invalid syntax here)};class Vexing { public: explicit Vexing(const std::string& s) { ... }; ...};void func() { Vexing v{std::string()}; // Using "()" here triggers "most vexing parse"; // "{}" is arguably more readable than "(())" ...不要將統(tǒng)一初始化結(jié)合auto使用auto x{1}; // Until C++17, decltype(x) is std::initializer_list<int>, not int!

優(yōu)先使用MakeUnique 替換WrapUnique

? base::MakeUnique(…) 和 base::WrapeUnique(new Type())是等同的,MakeUnique更好,因為通常來說用它很難寫出不安全的代碼。

return std::unique_ptr<C>(new C(1, 2, 3)); // BAD: type name mentioned twice return base::WrapUnique(new C(1, 2, 3)); // BAD: bare call to new return base::MakeUnique<C>(1, 2, 3); // GOOD

注意: MakeUnique就是C++14中的make_unique的實現(xiàn)

不要將MakeUnique設(shè)置為類的友元,因為這會讓任何人都可以構(gòu)造這個類 class Bad { public: std::unique_ptr<Bad> Create() { return base::MakeUnique<Bad>(); } // ... private: Bad(); // ... friend std::unique_ptr<Bad> base::MakeUnique<Bad>(); // Lost access control};class Okay { public: // For explanatory purposes. If Create() adds no value, it is better just // to have a public constructor instead. std::unique_ptr<Okay> Create() { return base::WrapUnique(new Okay()); } // ... private: Okay(); // ...}; 對于WrapUnique(new Foo) 和 WrapUnique(new Foo()) 來說,如果Foo沒有自定義的構(gòu)造函數(shù)的話那么這兩者的含義是不同的,不要讓未來的維護者猜測你是否是故意不寫(),使用MakeUnique()來替換,如果你是有意不寫()來作為優(yōu)化,請加上說明 auto a = base::WrapUnique(new A); // BAD: "()" omitted intentionally? auto a = base::MakeUnique<A>(); // GOOD // "()" intentionally omitted to avoid unnecessary zero-initialisation. // WrapUnique() does the wrong thing for array pointers. auto array = std::unique_ptr<A[]>(new A[size]);

不要使用auto來推導(dǎo)裸指針

? 鼓勵使用auto來從初始化表達式中進行類型推導(dǎo),但是當推導(dǎo)的是指針類型的時候不要使用auto,這會給使用者帶來疑惑,應(yīng)該使用auto*來替代,如下:

auto item = new Item(); // BAD: auto deduces to Item*, type of |item| is Item*auto* item = new Item(); // GOOD: auto deduces to Item, type of |item| is Item*
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表

圖片精選

主站蜘蛛池模板: 连南| 巴彦淖尔市| 宜兰县| 嘉义市| 安徽省| 珠海市| 阿尔山市| 驻马店市| 南澳县| 治县。| 灵山县| 伊宁县| 乌兰浩特市| 富宁县| 华阴市| 岳普湖县| 民县| 望城县| 巴青县| 商城县| 清水河县| 会宁县| 舞钢市| 姚安县| 白山市| 龙南县| 博兴县| 新蔡县| 盐亭县| 怀柔区| 松潘县| 榕江县| 昌都县| 长泰县| 葫芦岛市| 北京市| 洪湖市| 南和县| 龙川县| 金昌市| 平武县|