C++11新特性

std::this_thread::yield()

看代码如下:

while(true) {
    if(pool.try_get_work()) {
        // do work
    }
    else {
        std::this_thread::yield(); // other threads can push work to the queue now
    }
}

(1) std::this_thread::yield(); 是将当前线程所抢到的CPU”时间片A”让渡给其他线程(其他线程会争抢”时间片A”,
注意: 此时”当前线程”不参与争抢)。
等到其他线程使用完”时间片A”后, 再由操作系统调度, 当前线程再和其他线程一起开始抢CPU时间片.
(2) 如果将 std::this_thread::yield();上述语句修改为: return; ,则将未使用完的CPU”时间片A”还给操作系统, 再由操作系统调度, 当前线程和其他线程一起开始抢CPU时间片。
std::this_thread::yield() 是让线程让渡出自己的CPU时间片(给其他线程使用)
std::this_thread::sleep_for() 是线程根据某种需要, 需要等待若干时间.

noexcept

Lambda表达式

C++ 11 Lambda表达式

函数对象

函数对象(function object),也称仿函数(functor),通常来讲, 是指重载了函数调用操作符operator()的类所实例化的对象,该对象的行为类似于函数。

class Minus
{
public:
    int operator()(int iLeft, int iRight)
    {
        return iLeft - iRight;
    }
};

int main()
{
    Minus o_minus;
    int i_result = o_minus(10, 5);

    return 0;
}
函数对象和函数指针性能比较

函数对象相比函数指针,性能更高。因为调用operator()实质上是调用这个类成员的成员函数,而这个成员函数默认是inline的。但函数指针就是普通的调用函数,效率低。(这里要知道inline内联函数的优势)
参考Effective STL,条款46:C++的sort使用默认的函数对象总是比C里的qsort效率高。

智能指针

  1. 永远不要将new用在shared_ptr构造函数参数列表(shared_ptr<int> x = shared_ptr<int>(new int);)以外的地方。
  2. unique_ptr不支持普通的拷贝和赋值操作,不能用在STL标准容器中。
  3. auto_ptr不支持拷贝和赋值操作,不能用在STL标准容器中。

参考:shared_ptr和unique_ptr区别和联系
参考:智能指针的原理及实现
参考:浅谈shared_ptr及shared_ptr涉及到的循环引用问题
参考:C++ 智能指针(unique_ptr, shared_ptr)的源码分析

1. unique_ptr用法

unique_ptr <>不可复制,只能移动。

std::unique_ptr<int> ptr1;  // 空的unique_ptr对象
std::unique_ptr<Task> taskPtr(new Task(23));    // 使用原始指针创建
std::unique_ptr<Task> taskPtr2 = new Task();   // 编译错误。不能通过赋值创建

std::unique_ptr<Task> taskPtr3 = std::move(taskPtr);    // 传递所有权,taskPtr为空

//释放来自原始指针的对象的所有权
Task * ptr = taskPtr3.release();

2. shared_ptr用法

// 初始化
shared_ptr<int> x = shared_ptr<int>(new int); // 这个方法有缺陷,下面我会说
shared_ptr<int> y = make_shared<int>();
shared_ptr<Resource> obj = make_shared<Resource>(arg1, arg2); // arg1, arg2是Resource构造函数的参数
// 赋值
shared_ptr<int> z = x; // 此时z和x共享同一个引用计数器
// 像普通指针一样使用
int val = *x;
assert (x == z);
assert (y != z);
assert (x != nullptr);
obj->someMethod();
// 其它辅助操作
x.swap(z); // 交换两个shared_ptr管理的裸指针(当然,包含它们的引用计数)
obj.reset(); // 重置该shared_ptr(引用计数减1)

shared_ptr使用
shared_ptr 原理及事故

错误用法1:多个无关的shared_ptr管理同一裸指针

{
    int *a = new int;
    std::shared_ptr<int> p1(a);
    std::shared_ptr<int> p2(a);
    // shared_ptr<int> x = shared_ptr<int>(new int);  // 正确的用法,有缺陷
    std::cout << "p1 use_count:" << p1.use_count() << " p2 use_count:" << p2.use_count() << std::endl;  // 输出 1 1
}

p1和p2同时管理同一裸指针a,此时的p1和p2有着完全独立的两个引用计数器,计数器都为1(初始化p2时,用的是裸指针a,于是我们没有任何办法获取p1的引用计数!),于是,上面的代码会导致a被delete两次,分别由p1和p2的析构导致。
为了避免这种情况的发生,我们永远不要将new用在shared_ptr构造函数参数列表(shared_ptr<int> x = shared_ptr<int>(new int);)以外的地方,或者干脆不用new,改用make_shared。

错误用法2:循环引用。weak_ptr 解决shared_ptr循环引用问题

循环引用问题:

class B;
class A {
public:
    A() { cout << "A struct" << endl; }
    ~A() { cout << "~A" << endl; }
    void setB(shared_ptr<B> _b) { m_b = _b; }
private:
    shared_ptr<B> m_b;
};

class B {
public:
    B(shared_ptr<A> _a) : m_a(_a) { cout << "B struct" << endl; }   
    ~B() { cout << "~B" << endl; }
private:
    shared_ptr<A> m_a;
};

void test1()
{
    // 没有循环引用
    // 虽然a的引用计数会达到2,但在a/b实例析构时,分别会减去引用计数,而最终完成内存释放
    cout << "============ test1 start =============" << endl;
    shared_ptr<A> a = make_shared<A>(); // a
    cout << "a.use_count: " << a.use_count() << endl;
    shared_ptr<B> b = make_shared<B>(a);
    cout << "b.use_count: " << b.use_count() << endl;
    cout << "a.use_count: " << a.use_count() << endl;
    cout << "============ test1 end  =============" << endl;
}

void test2()
{
    // 循环引用
    cout << "============ test2 start =============" << endl;
    shared_ptr<A> a = make_shared<A>();
    cout << "a.use_count: " << a.use_count() << endl;
    shared_ptr<B> b = make_shared<B>(a);
    cout << "b.use_count: " << b.use_count() << endl;
    cout << "a.use_count: " << a.use_count() << endl;
    a->setB(b);
    cout << "b.use_count: " << b.use_count() << endl;
    cout << "============ test2 end  =============" << endl;
}

int main()
{
    test1();
    test2();
}

输出:
image.png

3 weak_ptr用法

用一个shared_ptr初始化weak_ptr

std::shared_ptr<int> sharedP(new int(5));
std::weak_ptr<int> weakP = sharedP;

weakP.lock()后会改变shared_ptr的引用计数(+1)

// weak_ptr不会改变shared_ptr,但是会和shared_ptr的引用保持一致
std::cout << "sharedP use_count:" << sharedP.use_count() << " weakP use_count:" << weakP.use_count() << std::endl;  // 1, 1

// weakP.lock()后会改变shared_ptr的引用计数(+1)
std::shared_ptr<int> sharedP2 = weakP.lock();
std::cout << "sharedP use_count:" << sharedP.use_count() << " weakP use_count:" << weakP.use_count() << std::endl;  // 2, 2

weak_ptr没有重载*,->操作符,因此不可直接通过weak_ptr使用对象,只能通过lock()使用shared_ptr来操作

// 编译报错,weak_ptr没有重载*,->操作符,因此不可直接通过weak_ptr使用对象,只能通过lock()使用shared_ptr来操作
//std::cout << " number is " << *weakP << std::endl;

sharedP.reset();
std::cout << "sharedP use_count:" << sharedP.use_count() << " weakP use_count:" << weakP.use_count() << std::endl;  // 0, 1

if (weakP.expired()) {
    std::cout << "shared_ptr object has been destory" << std::endl;  // 不会进入
}

std::shared_ptr<int> sharedP3 = weakP.lock();
std::cout << "sharedP3 use_count:" << sharedP3.use_count() << " weakP use_count:" << weakP.use_count() << std::endl;// 2, 2
std::cout << "number is " << *sharedP3 << std::endl;    // 5


C++ 11 创建和使用共享 weak_ptr

4. enable_shared_from_this

当类A被share_ptr管理,且在类A的成员函数里需要把当前类对象作为参数传给其他函数时,就需要传递一个指向自身的share_ptr。

struct Good : std::enable_shared_from_this<Good> // 注意:继承
{
public:
    std::shared_ptr<Good> getptr() {
        return shared_from_this();
    }
    ~Good() { std::cout << "Good::~Good() called" << std::endl; }
};
 
int main()
{
    // 大括号用于限制作用域,这样智能指针就能在system("pause")之前析构
    {
        std::shared_ptr<Good> gp1(new Good());
        std::shared_ptr<Good> gp2 = gp1->getptr();
        // 打印gp1和gp2的引用计数
        std::cout << "gp1.use_count() = " << gp1.use_count() << std::endl;
        std::cout << "gp2.use_count() = " << gp2.use_count() << std::endl;
    }
    system("pause");
}

C++11新特性之十:enable_shared_from_this

匿名空间

当定义一个命名空间时,可以忽略这个命名空间的名称:

     namespce {
         char c;
         int i;
         double d;
     }

编译器在内部会为这个命名空间生成一个唯一的名字,而且还会为这个匿名的命名空间生成一条using指令。所以上面的代码在效果上等同于:

     namespace __UNIQUE_NAME_ {
         char c;
         int i;
         double d;
     }
     using namespace __UNIQUE_NAME_;

在匿名命名空间中声明的名称也将被编译器转换,与编译器为这个匿名命名空间生成的唯一内部名称(即这里的__UNIQUE_NAME_)绑定在一起。还有一点很重要,就是这些名称具有internal链接属性,这和声明为static的全局名称的链接属性是相同的,即名称的作用域被限制在当前文件中,无法通过在另外的文件中使用extern声明来进行链接。如果不提倡使用全局static声明一个名称拥有internal链接属性,则匿名命名空间可以作为一种更好的达到相同效果的方法。C++ 新的标准中提倡使用匿名命名空间,而不推荐使用static,因为static用在不同的地方,涵义不同,容易造成混淆.另外,static不能修饰class。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,546评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,224评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,911评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,737评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,753评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,598评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,338评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,249评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,696评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,888评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,013评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,731评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,348评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,929评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,048评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,203评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,960评论 2 355

推荐阅读更多精彩内容

  • 很多人谈到c++,说它特别难,可能有一部分就是因为c++的内存管理吧,不像java那样有虚拟机动态的管理内存,在程...
    this_is_for_u阅读 364评论 0 0
  • 应用 当我们需要从堆上申请空间时,可以将new出来的指针交由智能指针管理,比如:shared_ptr a(new...
    里里角阅读 736评论 0 0
  • lamda表达式 Lambda表达式来源于函数式编程,说白就了就是在使用的地方定义函数,有的语言叫“闭包。如果la...
    ninedreams阅读 360评论 0 0
  • 表情是什么,我认为表情就是表现出来的情绪。表情可以传达很多信息。高兴了当然就笑了,难过就哭了。两者是相互影响密不可...
    Persistenc_6aea阅读 125,066评论 2 7
  • 16宿命:用概率思维提高你的胜算 以前的我是风险厌恶者,不喜欢去冒险,但是人生放弃了冒险,也就放弃了无数的可能。 ...
    yichen大刀阅读 6,052评论 0 4