多线程的weak_ptr需要使用enable_shared_from_this机制来把this从类内部传递出来,来持有shared_ptr。使用时,用weak_ptr的lock
函数返回shared_ptr,如果shared_ptr为null,则表明该对象已经被析构了。
参考:
https://mp.weixin.qq.com/s/32aeGOPaySjTmyKcjFKgYA
窥见C++11智能指针
https://www.cnblogs.com/wangkeqin/p/9351191.html
C++内存管理之shared_ptr
https://blog.csdn.net/River_Lethe/article/details/78734879
shared_ptr的使用和陷阱
https://blog.csdn.net/qq_38410730/article/details/105903979
weak_ptr弱引用智能指针详解
和auto的用法类似,auto不仅要推导类型,还要定义变量,而decltype则只进行类型推导。
int add(int x,int y){
return x+y;
}
int main(){
double i=0;
decltype(i) a; // double
decltype(add()) b; //int 注意括号。不带括号就是函数指针了。
}
参考:
https://www.cnblogs.com/npbool/p/3433360.html
C++11初探:类型推导,auto和decltype
static_cast:基本等同于C语言的强制类型转换,只有很小的差异。
dynamic_cast:主要用于类层次间的上行转换和下行转换。
const_cast:用于修改类型的const或volatile属性。
reinterpret_cast:它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针。
上面4个算是C++的基本类型变换。除此之外还有一些变种。
static_pointer_cast:Static cast of shared_ptr
dynamic_pointer_cast:Dynamic cast of shared_ptr
const_pointer_cast:Const cast of shared_ptr
template <class Derived, class Base>
inline Derived polymorphic_cast(Base* x);
// Throws: std::bad_cast if ( dynamic_cast<Derived>(x) == 0 )
// Returns: dynamic_cast<Derived>(x)
template <class Derived, class Base>
inline Derived polymorphic_downcast(Base* x);
// Effects: assert( dynamic_cast<Derived>(x) == x );
// Returns: static_cast<Derived>(x)
template <class Derived, class Base>
inline auto polymorphic_pointer_cast(Base x);
// Throws: std::bad_cast if ( dynamic_pointer_cast<Derived>(x) == 0 )
// Returns: dynamic_pointer_cast<Derived>(x)
template <class Derived, class Base>
inline auto polymorphic_pointer_downcast(Base x);
// Effects: assert( dynamic_pointer_cast<Derived>(x) == x );
// Returns: static_pointer_cast<Derived>(x)
参考:
https://www.cnblogs.com/chenyangchun/p/6795923.html
C++强制类型转换:static_cast、dynamic_cast、const_cast、reinterpret_cast
void f(int n1, int n2, int n3, const int& n4, int n5)
{
std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << '\n';
}
auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5);
f2(10, 11, 12); // 进行到 f(12, g(12), 12, 4, 5); 的调用
int sum(int count, ...)
{
va_list vl;
int sum = 0;
va_start(vl, count);
for (int i = 0; i < count; ++i)
{
sum += va_arg(vl, int);
}
va_end(vl);
return sum;
}
上面是C风格的变参函数,主要依赖了va_xx系列函数。
template<typename T>
void Append(Optimizer::Optimizations& optimizations, T&& optimization)
{
optimizations.emplace_back(new T(optimization));
};
template<typename Front, typename... Others>
void Append(Optimizer::Optimizations& optimizations, Front&& front, Others&&... others)
{
Append<Front>(optimizations, std::forward<Front>(front));
Append<Others...>(optimizations, std::forward<Others>(others)...);
};
template<typename... Args>
Optimizer::Optimizations MakeOptimizations(Args&&... args)
{
Optimizer::Optimizations optimizations;
Append(optimizations, std::forward<Args>(args)...);
return optimizations;
}
上面是C++风格的变参函数。它主要采用了Parameter pack技术,简单的说就是递归的模板展开。
以上面的函数为例:
1.首先使用第2个模板函数展开函数。
2.在第2个模板函数中调用第1个模板函数,而第1个模板函数不是变参函数,相当于是递归的结尾。
std::tuple、std::bind等的实现都借助了Parameter pack。
在C++17中,还提出一个叫做fold expression的技术。
template<typename ...Args>
int sum(Args&&... args) {
// return (args + ... + 1 * 2); // Error: operator with precedence below cast
return (args + ... + (1 * 2)); // OK
}
上述函数是一个对+
运算符的fold expression。
再来一个dispatch的例子:
CheckDispatch<bool, float, double, uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t>();
template <typename Type, typename Next, typename... Types>
void CheckDispatch() {
if (type == GetType<Type>())
Check<Type>();
else
CheckDispatch<Next, Types...>();
}
template <>
void Check<float>() {
//do sth
}
参考:
https://www.jianshu.com/p/d22904f30930
C++11新特性–不定参数模板与std::tuple、std::bind实现原理
template<class T1, class T2> // 普通版本,有两个模板参数
class B { ..... };
template<class T2> // 偏特化版本,指定其中一个参数,即指定了部分类型
class B<int , T2> { ..... };// 当实例化时的第一个参数为int 则会优先调用这个版本
偏特化的条件:
1.必须有一个主模板。
2.模板类型被部分明确化。
相应的,如果模板参数全被指定,则为全特化。
对主版本模板类、全特化类、偏特化类的调用优先级从高到低进行排序是:全特化类>偏特化类>主版本模板类。
traits一方面,在面对不同的输入类时,能找到合适的返回型别;另一方面,当型别对应有不同的实现函数的时候,能起到一个提取型别然后分流的作用。
标准库已经内置了一些常见的traits操作,例如std::pointer_traits,该模板可返回迭代器指向对象的型别。
参考:
https://www.cnblogs.com/yyehl/p/7253254.html
C++ 模板偏特化-来自STL的思考
https://www.cnblogs.com/mangoyuan/p/6446046.html
C++ traits技术浅谈
vector<T>::size_type
可能有三种解释:
静态数据成员
静态成员函数
嵌套类型
前两者比较好区分,函数名后一般有括号。但是嵌套类型就不好区分了,因此需要用typename关键字指定之。
参考:
https://blog.csdn.net/zhangxiao93/article/details/50569924
C++ typedef typename作用
typeid可用于打印类型名称。这里的类型可以是固定类型,也可以是模板类型。
cout << typeid(int).name() << typeid(T).name() << endl;
以下是一个复杂的例子,用于处理shared_ptr+派生类的情况:
std::vector<std::shared_ptr<A>> a;
class B : public A;
class C : public A;
a.push_back(std::make_shared<B>());
auto a0 = a[0];
cout << typeid(*a0).name() << endl;
std::reference_wrapper<const std::type_info> AInfo = typeid(A);
typeid(*p) == AInfo.get()
if (std::is_same<float, T>::value) {
//do sth
}
for (auto i : v) // access by value, the type of i is int
std::cout << i << ' ';
长期以来,C/C++的线程编程主要依赖pthread库,但是这个情况在C++ 11之后有所改观,因为C++ 11的标准库已经支持thread了。
thread基本用法:
https://www.runoob.com/w3cnote/cpp-std-thread.html
std::thread
配合thread还提出了thread_local关键字:
https://www.cnblogs.com/pop-lar/p/5123014.html
thread_local变量
mutex同步:
https://www.cnblogs.com/xudong-bupt/p/9194394.html
C++并发编程,std::unique_lock与std::lock_guard区别示例
条件等待:
http://hengyunabc.github.io/cpp11-mutex-lock-condition/
C++11中的mutex, lock,condition variable实现分析
https://www.zhihu.com/question/24116967
pthread_cond_wait为什么需要传递mutex参数?
https://segmentfault.com/a/1190000006679917
条件变量(Condition Variable)
condition variable的wait操作会释放锁,并挂起当前线程。
class Point {
public:
int x, y;
Point(int x = 0, int y = 0)
: x(x), y(y) {}
};
void displayPoint(const Point& p)
{
cout << "(" << p.x << ","
<< p.y << ")" << endl;
}
int main()
{
displayPoint(1);
Point p = 1;
}
上面代码片段中,displayPoint(1);
粗看起来是不能执行的,因为1不是一个Point。然而C++编译器要比C聪明一点,它发现,1是Point构造函数的合法参数,于是自动调用之。即:displayPoint(1);
等价于displayPoint(Point(1));
然而有的时候,为了代码的健壮,我们不想让别人用这样不正式的方式创建对象,这时可以通过将构造函数声明为explicit,来防止隐式类型转换。
explicit关键字只能用于类内部的构造函数声明上,而不能用在类外部的函数定义上。
参考:
https://zhuanlan.zhihu.com/p/52152355
C++ explicit 关键字
template<typename To, typename From> To convert(From f);
void g(double d)
{
int i = convert<int>(d); // 调用 convert<int, double>(double)
char c = convert<char>(d); // 调用 convert<char, double>(double)
int(*ptr)(float) = convert; // 实例化 convert<int, float>(float)
}
除了特化模板之外,从函数参数推断模板参数也是可以的,如上例中的模板参数From
就可以从使用该模板参数的函数参数f
的类型,倒推出来。
特殊成员函数主要包括:
1.默认构造函数(不带参数的构造函数)
2.析构函数
3.赋值函数(operator=)(按字节拷贝)
4.拷贝构造函数(用一个对象来初始化另一个对象,只有一个参数,参数类型是本类的引用。X(X&)
)(按字节拷贝)
5.移动构造函数(X(X&&)
)
6.移动赋值函数
其中,2、3、4被称为big three,2、3、4、5、6被称为big five。5、6是C++11中引入右值和move的结果。
https://www.jianshu.com/p/0b0f84b49736
C++缺省函数(big three,big five)
class X{
public:
X(int i){
a = i;
}
X(const X&) = delete;
X()=default;
private:
int a;
};
X x;
您的打赏,是对我的鼓励