空類(empty class)

空類就是沒有靜態(tài)成員變量的類店诗,卻通常帶有 typedef 和成員函數(shù)。


空類運(yùn)行時(shí)占用的空間

為保證不同的對(duì)象的地址是不同的,C++ 要求空類的大小不能為零。

class Empty { };

int main()
{
  std::cout << "sizeof(Empty): " << sizeof(Empty) << '\n';

  Empty arr[10];
  std::cout << "sizeof(arr): " << sizeof(arr) << '\n';

  Empty a, b;
  if (&a != &b) {
    std::cout << "the size of class Empty is not zero" << '\n';
  }
}

上述代碼結(jié)果如下(本文的測(cè)試環(huán)境為 Ubuntu-16.04-64bit GCC-5.4.0):

sizeof(Empty): 1
sizeof(arr): 10
the size of class Empty is not zero

如果 Empty 的大小為0秕狰,則無法區(qū)別 arr 中的十個(gè)元素。對(duì)于多數(shù)平臺(tái)躁染,Empty 的大小都是1鸣哀,但是部分平臺(tái)在對(duì)齊上有著較為嚴(yán)格的要求,結(jié)果可能會(huì)是一個(gè)字的大型掏(比如8)我衬。
對(duì)于帶有虛函數(shù)的空類:

class EmptyWithVirtualFunc
{
public:
  virtual void VirtualFunc() { }
};

int main()
{
  std::cout << "sizeof(EmptyWithVirtualFunc): " << sizeof(EmptyWithVirtualFunc) << '\n';
  std::cout << "sizeof(void*): " << sizeof(void*) << '\n';
}

結(jié)果如下:

sizeof(EmptyWithVirtualFunc): 8
sizeof(void*): 8

帶有虛函數(shù)的空類,編譯器會(huì)在該空類對(duì)象的起始位置(所有非靜態(tài)成員變量之前)放置一個(gè)虛指針饰恕,所以該類的大小不是1而是一個(gè)指針的大小低飒。


空基類優(yōu)化

在 C++ 中有一個(gè)現(xiàn)象與上述相悖:在空類作為基類的情況下,子類的空間中可能不會(huì)出現(xiàn)多出來的那一個(gè)字節(jié)懂盐。 由于帶有虛函數(shù)的空類實(shí)質(zhì)上還是有一個(gè)隱藏的虛指針成員,不算是嚴(yán)格意義上的空類糕档,所以不參與空基類優(yōu)化莉恼。

單繼承

class Derived1 : public Empty { };

class Derived2 : public Empty
{
public:
  std::int32_t i32;
};

int main()
{
  std::cout << "sizeof(Derived1): " << sizeof(Devired1) << '\n';
  std::cout << "sizeof(Derived2): " << sizeof(Devired2) << '\n';
}

結(jié)果如下:

sizeof(Derived1): 1
sizeof(Derived2): 4

從結(jié)果可以看出,Empty 在沒有繼承情況下多出來的一個(gè)字節(jié)在子類中并沒有體現(xiàn)速那,這一個(gè)字節(jié)被“優(yōu)化”了俐银。
當(dāng)有子類繼承空類 Derived1,既多層繼承時(shí):

class Derived3 : public Derived1 { };

class Derived4 : public Derived1
{
public:
  std::int32_t i32;
};

int main()
{
  std::cout << "sizeof(Derived3): " << sizeof(Devired3) << '\n';
  std::cout << "sizeof(Derived4): " << sizeof(Devired4) << '\n';
}

結(jié)果如下:

sizeof(Derived3): 1
sizeof(Derived4): 4

從多層繼承的結(jié)果可以看出端仰,多出的那一個(gè)字節(jié)是否被優(yōu)化與空類的繼承層數(shù)無關(guān)捶惜。
但是在部分情況下,優(yōu)化效果會(huì)消失:

class Derived5 : public Empty
{
public:
  Empty e;
};

class Derived6 : public Empty
{
public:
  static Empty se;
};
Empty Derived6::se { };

class Derived7 : public Empty
{
public:
  std::int32_t i32;
  Empty e;
};

int main()
{
  std::cout << "sizeof(Derived5): " << sizeof(Devired5) << '\n';
  std::cout << "sizeof(Derived6): " << sizeof(Devired6) << '\n';
  std::cout << "sizeof(Derived7): " << sizeof(Devired7) << '\n';
}

結(jié)果如下:

sizeof(Derived5): 2
sizeof(Derived6): 1
sizeof(Derived7): 8

我們分析一下這三個(gè)子類的內(nèi)存布局荔烧,
Derived5:

此時(shí)空基類優(yōu)化失去了效果吱七。如果依然進(jìn)行優(yōu)化,則無法區(qū)分基類 Empty 和子類中的成員 Empty(注意子類 Derived5 中的 Empty 不是基類鹤竭,所以不參與優(yōu)化踊餐,一定會(huì)占用一個(gè)字節(jié))。
Derived6:

依然進(jìn)行空基類優(yōu)化臀稚。因?yàn)殪o態(tài)成員變量不屬于某個(gè)具體的類實(shí)例吝岭,不占用類實(shí)例的空間,所以此時(shí)基類 Empty 不會(huì)與靜態(tài)成員變量發(fā)生沖突,但是由于 Derived6 是空類窜管,所以還是要占用一個(gè)字節(jié)空間散劫。
Derived7:

依然進(jìn)行了空基類優(yōu)化。因?yàn)榛?Empty 與子類中的成員 Empty 的地址空間不是相連的幕帆,不發(fā)生沖突(注意此時(shí)優(yōu)化掉了基類 Empty 的一個(gè)字節(jié)获搏,并沒有優(yōu)化子類成員變量 Empty)。在子類成員 Empty 后補(bǔ)齊三個(gè)字節(jié)蜓肆,所以整體占用的空間是八個(gè)字節(jié)颜凯。

多重繼承

如果不同的空類同時(shí)作為一個(gè)類的基類時(shí),

class Empty1 { };

class MultiDerived : public Empty, public Empty1 { };

int main()
{
  std::cout << "sizeof(MultiDerived): " << sizeof(MultiDerived) << '\n';
}

結(jié)果如下:

sizeof(MultiDerived): 1

編譯器認(rèn)為不同的空類在子類的內(nèi)存空間是不會(huì)發(fā)生沖突的仗扬。
再考慮如下的情況症概,

class MultiDerived1 : public Empty { };
class MultiDerived2 : public Empty { };
class MultiDerived3 : public MultiDerived1, public MultiDerived2 { };

int main()
{
  std::cout << "sizeof(MultiDerived3): " << sizeof(MultiDerived3) << '\n';
}

結(jié)果如下(暫不考慮虛繼承):

sizeof(MultiDerived3): 2

MultiDerived3的內(nèi)存布局如下:

沒有進(jìn)行空基類優(yōu)化。由于 MultiDerived1 是一個(gè)(is-a)Empty早芭,而且 MultiDerived2 也是一個(gè) Empty彼城,又由于 MultiDerived1 和 MultiDerived2 在子類的內(nèi)存空間中是連續(xù)的,此時(shí)如果進(jìn)行了空基類優(yōu)化退个,則兩個(gè) Empty 就無法區(qū)分募壕。
再考慮如下的情況,

class NotEmpty
{
public:
  std::int32_t i32;
};

class MultiDerived4 : public MultiDerived1, public NotEmpty
{
public:
  Empty e;
};

class MultiDerived5 : public NotEmpty, public MultiDerived1
{
public:
  Empty e;
};

class MultiDerived6 : public NotEmpty, public MultiDerived1 { };

int main()
{
  std::cout << "sizeof(MultiDerived4): " << sizeof(MultiDerived4) << '\n';
  std::cout << "sizeof(MultiDerived5): " << sizeof(MultiDerived5) << '\n';
  std::cout << "sizeof(MultiDerived6): " << sizeof(MultiDerived6) << '\n';
}

結(jié)果如下:

sizeof(MultiDerived4): 8
sizeof(MultiDerived5): 8
sizeof(MultiDerived6): 4

我們分析一下這三個(gè)子類的內(nèi)存布局语盈,
MultiDerived4:

進(jìn)行了空基類優(yōu)化舱馅。由于 MultiDerived1 的 Empty 與子類成員 Empty 中間隔了 NotEmpty,所以不發(fā)生沖突刀荒,因此可以進(jìn)行優(yōu)化代嗤。
MultiDerived5:

沒有發(fā)生空基類優(yōu)化。因?yàn)?MultiDerived1 的 Empty 與子類成員 Empty 是連續(xù)的缠借,進(jìn)行優(yōu)化會(huì)發(fā)生沖突干毅。
MultiDerived6:

進(jìn)行了空基類優(yōu)化。因?yàn)?MultiDerived1 的 Empty 不會(huì)與其他 Empty 發(fā)生沖突泼返。

特殊的情況

再來看看比較特殊的情況硝逢,

class Foo
{
public:
  Empty e[4];
  Derived2 d;
};

class Foo1Helper : public Empty
{
public:
  std::int8_t i8[3];
};

class Foo1 : public Empty
{
public:
  Foo1Helper d;
};

class Foo2 : public Empty
{
public:
  Foo f;
};

int main()
{
  std::cout << "sizeof(Foo): " << sizeof(Foo) << '\n';
  std::cout << "sizeof(Foo1): " << sizeof(Foo1) << '\n';
  std::cout << "sizeof(Foo2): " << sizeof(Foo2) << '\n';
}

結(jié)果如下:

sizeof(Foo): 8
sizeof(Foo1): 4
sizeof(Foo2): 12

Foo 中的 Derived2 仍然進(jìn)行了空基類優(yōu)化,并沒有因?yàn)?Foo 中的成員 Empty 與 Derived2 的基類 Empty 相鄰而影響優(yōu)化绅喉,從“空基類優(yōu)化”這個(gè)名字也表明了該優(yōu)化只與繼承體系有關(guān)系渠鸽,而不考慮被優(yōu)化的類之外的干擾。
Foo1 也進(jìn)行了空基類優(yōu)化柴罐,但是比較特別拱绑,編譯器首先考慮的是將子類成員變量 Foo1Helper 進(jìn)行優(yōu)化(理由同 Foo1 中的 Derived2),此時(shí) Foo1Helper 內(nèi)存空間中已不存在 Empty丽蝎,所以也對(duì) Foo1 進(jìn)行了優(yōu)化猎拨。
Foo2 沒有發(fā)生空基類優(yōu)化膀藐,因?yàn)榈谝粋€(gè)成員 Foo 的第一個(gè)成員變量是 Empty,與基類中 Empty 發(fā)生了沖突红省。

結(jié)論

當(dāng)空類作為一個(gè)類的基類的時(shí)候额各,該空類占用的額外一個(gè)字節(jié)的內(nèi)存空間在子類中將會(huì)被優(yōu)化掉,除了一種情況外:在子類的內(nèi)存空間中有連續(xù)的相同類型的空類出現(xiàn)時(shí)(無論該空類是作為基類吧恃,超基類虾啦,子類的第一個(gè)非靜態(tài)成員變量,子類的第一個(gè)非靜態(tài)成員變量的基類痕寓,子類的第一個(gè)非靜態(tài)成員變量的成員傲醉,所有的這些都可以歸納為子類的內(nèi)存空間中基類的空間與接下來的第一個(gè)內(nèi)存塊),為了區(qū)分連續(xù)的空類呻率,將不進(jìn)行空基類優(yōu)化硬毕。
此外,在 C++11 中礼仗,空基類優(yōu)化是強(qiáng)制性的吐咳,不再是可選的。


空類的應(yīng)用

std::vector

在標(biāo)準(zhǔn)庫中元践,使用到分配器(allocator-aware)的類大多利用到了空基類優(yōu)化韭脊,進(jìn)而避免無狀態(tài)(stateless)的分配器成員占用額外的空間。

template <typename _Tp, typename _Alloc>
struct _Vector_base
{
  typedef _Alloc<_Tp> _Tp_alloc_type; // 分配器的具體類型
  typedef _Tp* pointer; // 存儲(chǔ)類型

  // 數(shù)據(jù)存儲(chǔ)的具體實(shí)現(xiàn)
  struct _Vector_impl : public _Tp_alloc_type
  {
    pointer _M_start; // 存儲(chǔ)的開始
    pointer _M_finish; // 存儲(chǔ)的結(jié)束
    pointer _M_end_of_storage; // 已經(jīng)分配的空間单旁,即capacity
  };
};

template <typename _Tp, typename _Alloc = std::allocator<_Tp>>
class vector : protected _Vector_base<_Tp, _Alloc>
{
};

以上是經(jīng)過簡(jiǎn)化的 std::vector 的代碼沪羔。我們需要關(guān)注的是 _Vector_base 中的 _Vector_impl。
對(duì)于 _Tp_alloc_type象浑,我們也可以不讓 _Vector_impl 繼承于 _Tp_alloc_type蔫饰,單獨(dú)設(shè)置一個(gè)成員變量,

template <typename _Tp, typename _Alloc>
struct _Vector_base
{
  typedef _Alloc<_Tp> _Tp_alloc_type; // 分配器的具體類型
  typedef _Tp* pointer; // 存儲(chǔ)類型

  // _Vector_impl利用該變量進(jìn)行內(nèi)存的分配
  _Tp_alloc_type _alloc;
    
  // 數(shù)據(jù)存儲(chǔ)的具體實(shí)現(xiàn)
  struct _Vector_impl
  {
    pointer _M_start; // 存儲(chǔ)的開始
    pointer _M_finish; // 存儲(chǔ)的結(jié)束
    pointer _M_end_of_storage; // 已經(jīng)分配的空間融柬,即capacity
  };
};

由于無狀態(tài)的分配器是空類,沒有任何成員變量趋距,這樣處理的話會(huì)白白浪費(fèi)了一個(gè)字節(jié)的存儲(chǔ)空間粒氧,像std::vector 這樣的使用率非常高的類來說,代價(jià)非常高节腐。
所以標(biāo)準(zhǔn)庫采用了空基類優(yōu)化外盯,將分配器額外的存儲(chǔ)空間優(yōu)化掉。

std::enable_if

template <bool _Cond, typename _Tp = void>
struct enable_if { };

template <typename _Tp>
struct enable_if<true, _Tp>
{
  typedef _Tp type;
};

以上是 GCC 中關(guān)于 std::enable_if 完整的代碼翼雀。
enable_if 是空類饱苟,但是這里與空基類優(yōu)化無關(guān)。當(dāng) _Cond 為 true 時(shí)狼渊,enable_if 進(jìn)行了部分模板特化箱熬,其中的 typedef 是關(guān)鍵类垦。
下面是 enable_if 的實(shí)例,

template <typename T>
typename std::enable_if<std::is_integral<T>::value,bool>::type is_odd(T i)
{
  return (i%2) == 1;
}

template <typename T, typename = typename std::enable_if<std::is_integral<T>::value>::type>
bool is_even(T i)
{
  return (i%2) == 0;
}

int main()
{
  int i { 2 }; // i是整型值
    
  std::cout << std::boolalpha; // bool值會(huì)展示成"true", "false"而不是"0", "1"
  std::cout << "i is odd: " << is_odd(i) << '\n';
  std::cout << "i is even: " << is_even(i) << '\n';

  double d { 2.0 }; // d是雙精度浮點(diǎn)數(shù)

  std::cout << "i is odd: " << is_odd(i) << '\n'; // ERROR, 編譯失敗
  std::cout << "i is even: " << is_even(i) << '\n'; // ERROR, 編譯失敗
}

結(jié)果如下:

i is odd: false
i is even: true

在上述的兩個(gè)例子中城须,_Cond 為 true 的模板特化中的 type 成為了關(guān)鍵蚤认,如果 _Cond 為 false,則使用type 會(huì)發(fā)生編譯錯(cuò)誤糕伐,因?yàn)樵谠椭袥]有 type砰琢。is_odd 利用的 type 作為返回值;is_even 則純粹是利用 type 作為編譯時(shí)的驗(yàn)證工具良瞧。

利用空類替代friend

關(guān)鍵字 friend 是一種強(qiáng)耦合陪汽,甚至強(qiáng)于繼承,所以我們應(yīng)當(dāng)小心地使用 friend 或者盡量避免褥蚯。
friend 的常見用途是訪問另一個(gè)類的私有構(gòu)造函數(shù)挚冤,

class Secret
{
  friend class SecretFactory;

private:
  // SecretFactory可以訪問該構(gòu)造函數(shù)
  explicit Secret(std::string str) : _data{std::move(str)} {}

  // SecretFactory同時(shí)也可以訪問該函數(shù),但是這可能會(huì)給我們?cè)斐陕闊?  void addData(const std::string& moreData) { _data.append(moreData); }

private:
  // SecretFactory無論如何也不應(yīng)該訪問該數(shù)據(jù)
  std::string _data;
};

在上述例子中遵岩,SecretFactory 可以訪問不該訪問的 _data你辣,這會(huì)添加很多麻煩。
我們可以通過空類來限制 SecretFactory 可以訪問的函數(shù)尘执,

class Secret
{
public:
  class ConstructorKey {
    // 如果其他的類想要訪問Secret的構(gòu)造函數(shù)舍哄,可以在這里添加友元
    friend class SecretFactory;
  private:
    // 構(gòu)造函數(shù)為private很關(guān)鍵
    ConstructorKey() {}; // ①
    ConstructorKey(const ConstructorKey&) = default; // ②
  };

  // 設(shè)置為public是為了讓SecretFactory訪問
  explicit Secret(std::string str, ConstructorKey) : _data{std::move(str)} {}

private:
  void addData(const std::string& moreData) { _data.append(moreData); }

  std::string _data;
};

class SecretFactory
{
public:
  Secret getSecret(std::string str) {
    // RVO
    return Secret { std::move(str), Secret::ConstructorKey{} };
  }

  void modify(Secret& secret, const std::string& additionalData) {
    // secret.addData(additionalData); // ERROR, addData是私有的,此時(shí)空類已經(jīng)限制了SecretFactory訪問Secret的函數(shù)
  }
};

int main()
{
  // Secret s { "Secret Class", ConstructorKey{} }; // ERROR, 無法訪問ConstructorKey的構(gòu)造函數(shù)

  SecretFactory sf;
  Secret s = sf.getSecret("Secret Class");
}

上例有兩點(diǎn)需要解釋誊锭,
對(duì)于①表悬,ConstructorKey 的構(gòu)造函數(shù)的訪問權(quán)限是 private,只有對(duì)其為 friend 的類才能訪問構(gòu)造函數(shù)丧靡;不能將構(gòu)造函數(shù)設(shè)置為 default蟆沫,即 ConstructorKey() = default;,對(duì)于沒有非靜態(tài)成員的類(空類)來講温治,即使默認(rèn)構(gòu)造為 private饭庞,依然可以通過統(tǒng)一初始化方式(uniform initialization)對(duì)其進(jìn)行初始化,

class EmptyUniIni
{
  EmptyUniIni() = default;
};

int main()
{
  EmptyUniIni empty; // ERROE, 無法訪問構(gòu)造函數(shù)
  EmptyUniIni empty1 {}; // OK, uniform initialization
}

對(duì)于②熬荆,需要將復(fù)制構(gòu)造函數(shù)設(shè)置為 private舟山,否則的話可以通過下面的代碼進(jìn)行構(gòu)造 Secret,

Secret::ConstructorKey* pk = nullptr;
Secret s { "Secret class", *pk };

這樣的話卤恳,我們前邊所做的努力就白費(fèi)了累盗。

std::input_iterator_tag, std::output_iterator_tag

// 用來標(biāo)記input iterator
struct input_iterator_tag { };

// 用來標(biāo)記output iterator
struct output_iterator_tag { };

// _Category即上述兩個(gè)標(biāo)簽
template <typename _Category, typename... _Others>
struct iterator { };

// 簡(jiǎn)略寫其他的template參數(shù)
template <typename... _Others>
class istream_iterator : public iterator<input_iterator_tag, _Others...>
{
};

template <typename... _Others>
class ostream_iterator : public iterator<output_iterator_tag, _Others...>
{
};

上述是簡(jiǎn)化的 GCC 代碼。
由于 C++ 是強(qiáng)類型語言突琳,input_iterator_tag 和 output_iterator_tag 雖然什么都沒有若债,只有名字不同,他們也是不同的類型拆融,所以 istream_iterator 的父類和 ostream_iterator 的父類是不同的蠢琳,他們?cè)诶^承層次上沒有任何關(guān)系啊终,即 input_iterator_tag 標(biāo)記了 istream_iterator,output_iterator_tag 標(biāo)記了ostream_iterator挪凑。
而且上述代碼不會(huì)有任何性能上的缺陷孕索,因?yàn)榫幾g器會(huì)檢查模板中的參數(shù)是否被使用,如果沒有使用躏碳,則將該模板參數(shù)省略掉搞旭,進(jìn)而不會(huì)影響性能。


總結(jié)

通過上述講解菇绵,我們了解了空類的一些特性與應(yīng)用場(chǎng)景肄渗,利用空基類優(yōu)化或者與模板結(jié)合起來,會(huì)有奇妙的效果咬最。


參考

[1] C++ Templates: The Complete Guide
[2] classes-and-objects
[3] Passkey Idiom: More Useful Empty Classes
[4] The "Empty Member" C++ Optimization
[5] Empty base optimization

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末翎嫡,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子永乌,更是在濱河造成了極大的恐慌惑申,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件翅雏,死亡現(xiàn)場(chǎng)離奇詭異圈驼,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)望几,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門绩脆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人橄抹,你說我怎么就攤上這事靴迫。” “怎么了楼誓?”我有些...
    開封第一講書人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵玉锌,是天一觀的道長。 經(jīng)常有香客問我疟羹,道長主守,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任阁猜,我火速辦了婚禮丸逸,結(jié)果婚禮上蹋艺,老公的妹妹穿的比我還像新娘剃袍。我一直安慰自己,他們只是感情好捎谨,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開白布民效。 她就那樣靜靜地躺著憔维,像睡著了一般。 火紅的嫁衣襯著肌膚如雪畏邢。 梳的紋絲不亂的頭發(fā)上业扒,一...
    開封第一講書人閱讀 49,741評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音舒萎,去河邊找鬼程储。 笑死,一個(gè)胖子當(dāng)著我的面吹牛臂寝,可吹牛的內(nèi)容都是我干的章鲤。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼咆贬,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼败徊!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起掏缎,我...
    開封第一講書人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤皱蹦,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后眷蜈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體沪哺,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年端蛆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了凤粗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡今豆,死狀恐怖嫌拣,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情呆躲,我是刑警寧澤异逐,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站插掂,受9級(jí)特大地震影響灰瞻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜辅甥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一酝润、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧璃弄,春花似錦要销、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纤掸。三九已至,卻和暖如春浑塞,著一層夾襖步出監(jiān)牢的瞬間借跪,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來泰國打工酌壕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留掏愁,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓卵牍,卻偏偏與公主長得像托猩,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子辽慕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348