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表达式
函数对象
函数对象(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效率高。
智能指针
- 永远不要将new用在shared_ptr构造函数参数列表(
shared_ptr<int> x = shared_ptr<int>(new int);
)以外的地方。 - unique_ptr不支持普通的拷贝和赋值操作,不能用在STL标准容器中。
- 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)
错误用法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。
网友评论