C++ primer 第十九章-特殊工具與技巧

Hi询吴!這里是山幺幺的c++ primer系列杯矩。寫這個系列的初衷是,雖然在學(xué)校學(xué)習(xí)了c++巾表,但總覺得對這門語言了解不深汁掠,因此我想來啃啃著名的c++ primer,并在這里同步記錄我的學(xué)習(xí)筆記集币。由于我啃的是英文版考阱,所以筆記是中英文夾雜的那種。另外由于已有一定的編程基礎(chǔ)鞠苟,所以這個系列不會含有太基礎(chǔ)的知識乞榨,想入門的朋友最好自己啃書嘻嘻~

控制內(nèi)存分配


重載new和delete

  • new expression
    • operator new function is used when we allocate an object; operator new[] is called when we allocate an array
    • 栗子
    string *sp = new string("a value"); // allocate and initialize a string
    string *arr = new string[10]; // allocate ten default initialized strings
    
    • 執(zhí)行步驟
      1. the expression calls a library function named operator new (or operator new[]),這個方程會allocates raw, untyped memory large enough to hold an object (or an array of objects) of the specified type
      2. compiler runs the appropriate constructor to construct the object(s) from the specified initializers
      3. a pointer to the newly allocated and constructed object is returned
  • delete expression
    • 栗子
    delete sp; // destroy *sp and free the memory to which sp points
    delete [] arr; // destroy the elements in the array and free the memory
    
    • 執(zhí)行步驟
      1. the appropriate destructor is run on the object to which sp points or on the elements in the array to which arr points
      2. the compiler frees the memory by calling a library function named operator delete or operator delete[]
  • 通過重載operator new and operator delete functions來重載new和delete:when the compiler sees a new or delete expression, it looks for the corresponding operator function to call当娱;先在成員函數(shù)中找(如果是類的話)吃既,再在global空間中找,最后用library函數(shù)
  • library new & delete:可以重載下面的任一版本趾访,重載的函數(shù)必須是類成員函數(shù)或在global scope
// these versions might throw an exception (delete肯定不會拋出異常)
void *operator new(size_t); // allocate an object
void *operator new[](size_t); // allocate an array
void *operator delete(void*) noexcept; // free an object
void *operator delete[](void*) noexcept; // free an array
// versions that promise not to throw
void *operator new(size_t, nothrow_t&) noexcept;
void *operator new[](size_t, nothrow_t&) noexcept;
void *operator delete(void*, nothrow_t&) noexcept;
void *operator delete[](void*, nothrow_t&) noexcept;
  • 若重載為成員函數(shù):
    • these operator functions are implicitly static:the member new and delete functions must be static because they are used either before the object is constructed (operator new) or after it has been destroyed (operator delete)
    • operator delete or operator delete[] may have a second parameter of type size_t态秧,它被initialized with the size in bytes of the object addressed by the first parameter(因為若基類有虛析構(gòu)函數(shù),要析構(gòu)的對象類型是動態(tài)綁定的)
  • operator new or operator new[]的要求:
    • 返回類型是void*
    • first parameter must have type size_t 且不能有默認值
    • 不能定義它(為library所保留):void operator new(size_t, void);
  • operator delete or operator delete[]的要求:
    • 返回類型是void
    • first parameter must have type void* (指向要free的內(nèi)存)
  • 重載函數(shù)的內(nèi)容:使用malloc and free
    • malloc:takes a size_t that says how many bytes to allocate扼鞋;returns a pointer to the memory that it allocated, or 0 if it was unable to allocate
    • free:takes a void* that is a copy of a pointer that was returned from malloc申鱼;returns the associated memory to the system;free(0) has no effect
    • 栗子
    void *operator new(size_t size) {
      if (void *mem = malloc(size))
        return mem;
      else
        throw bad_alloc();
    }
    void operator delete(void *mem) noexcept { free(mem); }
    

placement new expression

  • 格式:place_address是指針(不一定指向動態(tài)內(nèi)存)云头,initializers用來construct the newly allocated object
new (place_address) type
new (place_address) type (initializers)
new (place_address) type [size]
new (place_address) type [size] { braced initializer list }
  • When passed a single argument that is a pointer, a placement new expression constructs an object but does not allocate memory
  • 與allocator的construct的區(qū)別:the pointer that we pass to construct must point to space allocated by the same allocator object捐友;the pointer that we pass to placement new need not point to memory allocated by operator new

析構(gòu)

  • like calling destroy, calling a destructor destroys an object but does not free the memory
string *sp = new string("a value"); // allocate and initialize a string
sp->~string();

Run-Time Type Identification(RTTI)


概述

  • RTTI operators:
    • typeid:returns the type of a given expression
    • dynamic_cast:safely converts a pointer or reference to a base type into a pointer or reference to a derived type
  • when applied to pointers or references to types that have virtual functions, RTTI operators use the dynamic type of the object to which the pointer or reference is bound
  • 使用場景:I f we cannot use a virtual, we can use one of the RTTI operators

dynamic_cast

  • 格式
    dynamic_cast<type*>(e)
    dynamic_cast<type&>(e)
    dynamic_cast<type&&>(e)
    
    1. type必須是class type,且該class有虛函數(shù)
    2. e的類型必須是其中一種:① a class type that is publicly derived from the target 'type'溃槐;② a public base class of the target 'type'匣砖;③ the same as the target 'type'
    3. 第一句中e必須是指針,第二句中e必須是左值,第三局中e必須是右值
  • If a dynamic_cast to a pointer type fails, the result is 0. If a dynamic_cast to a reference type fails, the operator throws an exception of type bad_cast
  • we can do a dynamic_cast on a null pointer; the result is a null pointer of the requested type
  • 栗子
// cast to 指針
if (Derived *dp = dynamic_cast<Derived*>(bp)) {
  // use the Derived object to which dp points
} else { // bp points at a Base object
  // use the Base object to which bp points
}

// cast to 引用
void f(const Base &b) {
  try {
    const Derived &d = dynamic_cast<const Derived&>(b);
    // use the Derived object to which b referred
  } catch (bad_cast) {
    // handle the fact that the cast failed
  }
}

typeid

  • 返回值:a reference to a const object of a library type named type_info, or a type publicly derived from type_info
  • typeid(e):
    • e的top-level const會被忽略
    • 當(dāng)e是引用時猴鲫,returns the type to which the reference refers
    • 當(dāng)e是lvalue of a class type that defines at least one virtual function对人,返回的是動態(tài)類型,e會被evaluate拂共;其他情況返回的是靜態(tài)類型牺弄,e不會被evaluate(因為compiler knows the static type without evaluating the expression)
      • p是nullptr時:若p指向的類型是有virtual的class,則typeid(p)會拋出bad_typeid異常宜狐,因為p在運行時被evaluate了势告;若p指向的是其他類型,則typeid(*p)是合法的
  • 栗子:第二句話后抚恒,bp是Base*類型咱台,但指向a Derived object的base-part;dp是Derived類型
Derived *dp = new Derived;
Base *bp = dp; // both pointers point to a Derived object
// compare the type of two objects at run time
if (typeid(*bp) == typeid(*dp)) {
  // if bp and dp point to objects of the same type
}
// test whether the run-time type is a specific type
if (typeid(*bp) == typeid(Derived)) {
  // if bp actually points to a Derived
}

type_info類

  • 不同編譯器中type_info類的定義不同俭驮,但一定會包括這些:
  • 其他性質(zhì)
    • 有public virtual destructor回溺,因為type_info經(jīng)常作為基類
    • 沒有默認構(gòu)造函數(shù)
    • copy and move constructors and the assignment operators are all defined as deleted
    • 我們不能define, copy, or assign objects of type type_info
    • 唯一創(chuàng)建type_info對象的方式:typeid operator
  • 栗子:注意不同編譯器打出的名字不同
int arr[10];
Derived d;
Base *p = &d;
cout << typeid(42).name() << ", "
  << typeid(arr).name() << ", "
  << typeid(Sales_data).name() << ", "
  << typeid(std::string).name() << ", "
  << typeid(p).name() << ", "
  << typeid(*p).name() << endl;

枚舉


概述

  • 和類一樣,每個枚舉都定義了一個新類型
  • enumerations are literal types
  • enumerator:即{}中的那些表鳍,比如下面代碼中的input馅而、output、append譬圣、red瓮恭、yellow等
  • 分類
    • scoped
    enum class open_modes {input, output, append}; // 或者
    enum struct open_modes {input, output, append};
    
    • unscoped
    enum color {red, yellow, green}; // unscoped enumeration
    // unnamed, unscoped enum
    enum {floatPrec = 6, doublePrec = 10, double_doublePrec = 10};
    

enumerator

  • 可見性
    • scoped enumeration中的enumerators are inaccessible outside the scope of the enumeration
    • unscoped enumeration中的enumerators are placed into the same scope as the enumeration itself
    • 栗子
    enum color {red, yellow, green}; // unscoped enumeration
    enum stoplight {red, yellow, green}; // error: redefines enumerators
    enum class peppers {red, yellow, green}; // ok: enumerators are hidden
    color eyes = green; // ok: enumerators are in scope for an unscoped enumeration
    peppers p = green; // error: enumerators from peppers are not in scope
    // color::green is in scope but has the wrong type
    color hair = color::red; // ok: we can explicitly access the enumerators
    peppers p2 = peppers::red; // ok: using red from peppers
    
    • enumerators are constant expressions,所以
      • if initialized, their initializers must be constant expressions
      • we can use an enum as the expression in a switch statement and use the value of its enumerators as the case labels
      • we can also use an enumeration type as a nontype template parameter
      • we can initialize class static data members of enumeration type inside the class definition
    • 默認情況下厘熟,enumerator values start at 0 and each enumerator has a value 1 greater than the preceding one
    • 也可以自定義初始值
    enum class intTypes {
       charTyp = 8, shortTyp = 16, intTyp = 16,
       longTyp = 32, long_longTyp = 64
    };
    
  • 類型轉(zhuǎn)換
    • objects or enumerators of an unscoped enumeration type are automatically converted to an integral type
    int i = color::red; // ok: unscoped enumerator implicitly converted to int
    int j = peppers::red; // error: scoped enumerations are not implicitly converted
    

枚舉型對象

  • 只要枚舉類型有名字屯蹦,就可以定義該類型的對象
  • 枚舉型對象may be initialized or assigned only by one of its enumerators or by another object of the same enum type
open_modes om = 2; // error: 2 is not of type open_modes
om = open_modes::input; // ok: input is an enumerator of open_modes

specifying the size of an enum

enum intValues : unsigned long long {
  charTyp = 255, shortTyp = 65535, intTyp = 65535,
  longTyp = 4294967295UL,
  long_longTyp = 18446744073709551615ULL
};

PS:不指定的話,scoped enum默認用int绳姨,unscoped沒有默認用的類型(每個機器不同)
PS:it is an error for an enumerator to have a value that is too large to fit in that type(包括默認用int的情況)

forward declare an enum

  • c++ 11新特性
  • enum forward declaration must specify (implicitly or explicitly) the underlying size of the enum
// forward declaration of unscoped enum named intValues
enum intValues : unsigned long long; // unscoped, must specify a type
enum class open_modes; // scoped enums can use int by default

栗子

// unscoped enumeration; the underlying type is machine dependent
enum Tokens {INLINE = 128, VIRTUAL = 129};
void ff(Tokens);
void ff(int);
int main() {
  Tokens curTok = INLINE;
  ff(128); // exactly matches ff(int)
  ff(INLINE); // exactly matches ff(Tokens)
  ff(curTok); // exactly matches ff(Tokens)
  return 0;
}

指向類成員的指針


概述

  • 指向類成員的指針即a pointer that can point to a nonstatic member of a class:因為static class members are not part of any object登澜,所以指向靜態(tài)成員的指針就是普通指針
  • type of a pointer to member embodies both the type of a class and the type of a member of that class
  • 以下會用到的類
class Screen {
public:
  typedef std::string::size_type pos;
  char get_cursor() const { return contents[cursor]; }
  char get() const;
  char get(pos ht, pos wd) const;
private:
  std::string contents;
  pos cursor;
  pos height, width;
};

指向數(shù)據(jù)成員的指針

  • 定義和初始化
// pdata can point to a string member of a const (or non const) Screen object
const string Screen::*pdata;
pdata = &Screen::contents;
  • 使用:必須和對象綁定才能獲得值
Screen myScreen, *pScreen = &myScreen;
// .* dereferences pdata to fetch the contents member from the object myScreen
auto s = myScreen.*pdata;
// ->* dereferences pdata to fetch contents from the object to which pScreen points
s = pScreen->*pdata;
  • 作為函數(shù)返回值
class Screen {
public:
  // data is a static member that returns a pointer to member
  static const std::string Screen::*data() { return &Screen::contents; }
  // other members as before
};

// data() returns a pointer to the contents member of class Screen
const string Screen::*pdata = Screen::data();
// fetch the contents of the object named myScreen
auto s = myScreen.*pdata;

指向成員函數(shù)的指針

  • 聲明和初始化
char (Screen::*pmf2)(Screen::pos, Screen::pos) const; // 聲明
pmf2 = &Screen::get; // 初始化
  • 與普通函數(shù)指針的不同:no automatic conversion between a member function and a pointer to that member
// pmf points to a Screen member that takes no arguments and returns char
pmf = &Screen::get; // must explicitly use the address-of operator
pmf = Screen::get; // error: no conversion to pointer for member functions
  • 用法
Screen myScreen,*pScreen = &myScreen;
// call the function to which pmf points on the object to which pScreen points
char c1 = (pScreen->*pmf)();
// passes the arguments 0, 0 to the two-parameter version of get on the object myScreen
char c2 = (myScreen.*pmf2)(0, 0);
  • type aliases
// Action is a type that can point to a member function of Screen
// that returns a char and takes two pos arguments
using Action = char (Screen::*)(Screen::pos, Screen::pos) const;

Action get = &Screen::get; // get points to the get member of Screen

// action takes a reference to a Screen and a pointer to a Screen member function
Screen& action(Screen&, Action = &Screen::get);
Screen myScreen;
// equivalent calls:
action(myScreen); // uses the default argument
action(myScreen, get); // uses the variable get that we previously defined
action(myScreen, &Screen::get); // passes the address explicitly
  • 用作Callable Objects
    • 在與對象綁定前,指向成員函數(shù)的指針并不是callable
    auto fp = &string::empty; // fp points to the string empty function
    // error: must use .* or ->* to call a pointer to member
    find_if(svec.begin(), svec.end(), fp);
    
    • 法一:用function
    vector<string*> pvec;
    function<bool (const string*)> fp = &string::empty;
    // fp takes a pointer to string and uses the ->* to call empty
    find_if(pvec.begin(), pvec.end(), fp);
    
    • 法二:用mem_fn:可以推斷函數(shù)的形參類型和返回類型
    vector<string> svec;
    find_if(svec.begin(), svec.end(), mem_fn(&string::empty));
    
    auto f = mem_fn(&string::empty); // f takes a string or a string*
    f(*svec.begin()); // ok: passes a string object; f uses .* to call empty
    f(&svec[0]); // ok: passes a pointer to string; f uses .-> to call empty
    
    • 法三:用bind
    // bind each string in the range to the implicit first argument to empty
    auto it = find_if(svec.begin(), svec.end(), bind(&string::empty, _1));
    
    auto f = bind(&string::empty, _1);
    f(*svec.begin()); // ok: argument is a string f will use .* to call empty
    f(&svec[0]); // ok: argument is a pointer to string f will use .-> to call empty
    

嵌套類


概述

  • objects of the enclosing and nested classes are independent from each other(即object of the nested(enclosing) type does not have members defined by the enclosing(nested) class飘庄;且enclosing(nested) class has no special access to the members of a nested(enclosing) class)
  • 可見性:name of a nested class is visible within its enclosing class scope but not outside the class
  • a nested class defines a type member in its enclosing class

聲明+在enclosing class外定義嵌套類

  • 因為嵌套類是enclosing class的type member脑蠕,所以在使用嵌套類之前必須聲明它
  • 栗子
class TextQuery {
public:
  class QueryResult; // nested class to be defined later
  // other members
};

// we're defining the QueryResult class that is a member of class TextQuery
class TextQuery::QueryResult {
  // in class scope, we don't have to qualify the name of the QueryResult parameters
  friend std::ostream&
  print(std::ostream&, const QueryResult&);
public:
  // no need to define QueryResult::line_no; a nested class can use a member
  // of its enclosing class without needing to qualify the member's name
  QueryResult(std::string, std::shared_ptr<std::set<line_no>>, std::shared_ptr<std::vector<std::string>>);
  // other members
};

TextQuery::QueryResult::QueryResult(string s, shared_ptr<set<line_no>> p, shared_ptr<vector<string>> f)
: sought(s), lines(p), file(f) { }

定義嵌套類的靜態(tài)成員

  • 必須寫在enclosing class的scope外
int TextQuery::QueryResult::static_mem = 1024;

name lookup

  • a nested class is a nested scope

Union:節(jié)省空間的類


概述

  • a union may have multiple data members, but at any point in time, only one of the members may have a value
  • union所占空間大小:at least as much as is needed to contain its largest data member
  • union的成員不能是引用
  • 默認情況下跪削,members of a union are public
  • union may define member functions, including constructors and destructors
  • union不能繼承&被繼承谴仙,所以也沒有虛函數(shù)

定義&初始化Union

  • 栗子:有名union(if an initializer is present, it is used to initialize the first member)
// objects of type Token have a single member, which could be of any of the listed types
union Token {
  // members are public by default
  char cval;
  int ival;
  double dval;
};

Token first_token = {'a'}; // initializes the cval member(初始化第一個元素)
Token last_token; // uninitialized Token object
Token *pt = new Token; // pointer to an uninitialized Token object

last_token.cval = 'z';
pt->ival = 42;
  • 栗子:無名union(members of an anonymous union are directly accessible in the scope where the anonymous union is defined;無名union不能有private/protected成員碾盐;無名union不能有成員函數(shù))
union { // anonymous union
  char cval;
  int ival;
  double dval;
}; // defines an unnamed object, whose members we can access directly

cval = 'c'; // assigns a new value to the unnamed, anonymous union object
ival = 42; // that object now holds the value 42

unions with Members of Class Type

  • when we switch the union’s value to and from a member of class type, we must construct or destroy that member
  • when a union has members of built-in type, the compiler will synthesize the memberwise versions of the default constructor or copy-control members晃跺;但若 union 有一個類,它定義了 one of these members, the compiler synthesizes the corresponding member of the union as deleted
  • if a class has a union member that has a deleted copy-control member, then that corresponding copy-control operation(s) of the class itself will be deleted as well

Local Classes


概述

  • 定義:定義在函數(shù)體內(nèi)的類
  • 特點
    • visible only in the scope in which it is defined
    • all members, including functions, of a local class must be completely defined inside the class body
    • 不能定義靜態(tài)成員
    • 能直接access的:type names, static variables, and enumerators defined within the enclosing local scopes
    int a, val;
    void foo(int val) {
      static int si;
      enum Loc { a = 1024, b };
      // Bar is local to foo
      struct Bar {
        Loc locVal; // ok: uses a local type name
        int barVal;
        void fooBar(Loc l = a) { // ok: default argument is Loc::a
          barVal = val; // error: val is local to foo
          barVal = ::val; // ok: uses a global object
          barVal = si; // ok: uses a static local object
          locVal = b; // ok: uses an enumerator
        }
      };
      // . . .
    }
    

enclosing function的權(quán)限

  • enclosing function has no special access privileges to the private members of the local class

name lookup

  • if a name is not found as a class member, then the search continues in the enclosing scope and then out to the scope enclosing the function itself

nested local class

void foo() {
  class Bar {
  public:
  // ...
    class Nested; // declares class Nested
  };
  // definition of Nested
  class Bar::Nested {
  // ...
  };
}

Inherently Nonportable Features


定義

  • machine specific features

the sizes of the arithmetic types vary across machines

memory layout of a bit-field is machine dependent

P1045-1047

the precise meaning of volatile is inherently machine dependent

  • volatile的含義:an object should be declared volatile when its value might be changed in ways outside the control or detection of the program(比如program might contain a variable updated by the system clock)
  • volatile的作用:告訴編譯器不要 perform optimizations on such objects
  • volatile可用來修飾變量/成員函數(shù)
volatile int display_register; // int value that might change
volatile Task *curr_task; // curr_task points to a volatile object
volatile int iax[max_size]; // each element in iax is volatile
volatile Screen bitmapBuf; // each member of bitmapBuf is volatile
  • only volatile member functions may be called on volatile objects
  • volatile與指針:we may assign the address of a volatile object (or copy a pointer to a volatile type) only to a pointer to volatile毫玖;we may use a volatile object to initialize a reference only if the reference is volatile
volatile int v; // v is a volatile int
int *volatile vip; // vip is a volatile pointer to int
volatile int *ivp; // ivp is a pointer to volatile int
// vivp is a volatile pointer to volatile int
volatile int *volatile vivp;
int *ip = &v; // error: must use a pointer to volatile
*ivp = &v; // ok: ivp is a pointer to volatile
vivp = &v; // ok: vivp is a volatile pointer to volatile
  • synthesized copy/move and assignment operators cannot be used to initialize or assign from a volatile object:因為synthesized members take parameters that are references to (nonvolatile) const

Linkage Directives: extern "C"

  • C+ + uses linkage directives to indicate the language used for any non-C+ + function
  • linkage directives may not appear inside a class or function definition
  • 對compound-statement linkage directive而言:the names of functions declared within the braces are visible as if the functions were declared outside the braces
  • 栗子
// illustrative linkage directives that might appear in the C++ header <cstring>
// single-statement linkage directive
extern "C" size_t strlen(const char *);
// compound-statement linkage directive
extern "C" {
  int strcmp(const char*, const char*);
  char *strcat(char*, const char*);
}
// compound-statement linkage directive
extern "C" {
  #include <string.h> // C functions that manipulate C-style strings
}
  • the language in which a function is written is part of its type
void (*pf1)(int); // points to a C++ function
extern "C" void (*pf2)(int); // points to a C function
pf1 = pf2; // error: pf1 and pf2 have different types
  • 指向用其他語言寫的函數(shù)的指針必須be declared with the same linkage directive as 它指向的函數(shù)
// pf points to a C function that returns void and takes an int
extern "C" void (*pf)(int);
  • linkage directive applies to the function and any function pointers used as the return type or as a parameter type
// f1 is a C function; its parameter is a pointer to a C function
extern "C" void f1(void(*)(int));

所以如果想要pass a pointer to a C function to a C+ + function掀虎,需要用type alias:

// FC is a pointer to a C function
extern "C" typedef void FC(int);
// f2 is a C++ function with a parameter that is a pointer to a C function
void f2(FC *);
  • Exporting Our C+ + Functions to Other Languages:編譯器在處理下面的代碼時會generate code appropriate to the indicated language
// the calc function can be called from C programs
extern "C" double calc(double dparm) { /* ... */ }
  • 預(yù)處理器allow the same source file to be compiled under either C or C+ +
#ifdef __cplusplus
// ok: we're compiling C++
extern "C"
#endif
int strcmp(const char*, const char*);
  • C不支持重載函數(shù)
// error: two extern "C" functions with the same name
extern "C" void print(const char*);
extern "C" void print(int);

// the C function can be called from C and C++ programs
// the C++ functions overload that function and are callable from C++
extern "C" double calc(double);
extern SmallInt calc(const SmallInt&);
extern BigNum calc(const BigNum&);
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末凌盯,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子烹玉,更是在濱河造成了極大的恐慌驰怎,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件二打,死亡現(xiàn)場離奇詭異砸西,居然都是意外死亡,警方通過查閱死者的電腦和手機址儒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來衅疙,“玉大人莲趣,你說我怎么就攤上這事”ヒ纾” “怎么了喧伞?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長绩郎。 經(jīng)常有香客問我潘鲫,道長,這世上最難降的妖魔是什么肋杖? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任溉仑,我火速辦了婚禮,結(jié)果婚禮上状植,老公的妹妹穿的比我還像新娘浊竟。我一直安慰自己,他們只是感情好津畸,可當(dāng)我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布振定。 她就那樣靜靜地躺著,像睡著了一般肉拓。 火紅的嫁衣襯著肌膚如雪后频。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天暖途,我揣著相機與錄音卑惜,去河邊找鬼。 笑死丧肴,一個胖子當(dāng)著我的面吹牛残揉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播芋浮,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼抱环,長吁一口氣:“原來是場噩夢啊……” “哼壳快!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起镇草,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤眶痰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后梯啤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體竖伯,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年因宇,在試婚紗的時候發(fā)現(xiàn)自己被綠了七婴。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡察滑,死狀恐怖打厘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情贺辰,我是刑警寧澤户盯,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站饲化,受9級特大地震影響莽鸭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜吃靠,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一硫眨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧巢块,春花似錦捺球、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至歹鱼,卻和暖如春泣栈,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背弥姻。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工南片, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人庭敦。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓疼进,卻偏偏與公主長得像,于是被迫代替她去往敵國和親秧廉。 傳聞我的和親對象是個殘疾皇子伞广,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,515評論 2 359