C++11新特性之字节对齐、多参数模版、placement new
1. 内存对齐
#pragma pack(push, 1) struct A { char a; int b; double c; char d[11]; }; #pragma pack(pop) #pragma pack(push, 2) struct B { char a; int b; double c; char d[11]; }; #pragma pack(pop) void main() { cout << sizeof(A) << endl; cout << sizeof(B) << endl; }
上面的代码演示了采用#pragma pack()方法实现内存对其。接下来介绍C++11中相关内存对其的方法。
1.1 alignas
alignas指定内存对其大小,有时候我们希望不按照默认的内存对齐方式来对齐,这时我们可以用alignas来指定内存对齐。
在C++11中,只要是一个编译期数值(#define, static const, template)都支持alignas,另外需要注意alignas只能改大不能改小,如果要改小可以使用上面提到的#pragma pack(1)
1.2 alignof和std::alignment_of
alignof用来获取内存对齐大小,用法比较简单:
A a;
cout << alignof(a) << endl;
alignof只能返回一个size_t,而std::alignment_of继承自std::integral_constant,拥有value_type,type,value成员
cout << std::alignment_of<A>::value << endl; >>>> 1
cout << std::alignment_of<B>::value << endl; >>>> 2
1.3 std::aligned_storage
std::aligned_storage可以看成一个内存对其的缓冲区,原型如下:
template<std::size_t Len, std::size_t Align = /*default-alignment*/>
struct aligned_storage;
Len表示所存储类型的sie,Align表示该类型的内存对齐大小
1.4 max_align_t和std::align
std::max_align_t用来返回当前平台的最大默认内存对齐类型,对于malloc返回的内存,其对齐和max_align_t类型的对齐大小应当是一致的。我们可以通过下面的方式获得当前平台的最大默认内存对齐数:
std::cout << alignof(std::max_align_t) << std::endl;
std::align用来在一大块内存中获取一个符合指定内存要求的地址
char buffer[] = "......"; void *ptr = buffer; std::size_t space = sizeof(buffer) - 1; std::align(alignof(int),sizeof(char),pt,space);
2. 示例
2.1. optional类实现
// 实现boost中的optional类 // 该类可以存储任意类型的数据 // int float string struct #pragma once using namespace std; template <typename T> class COptional { public: // alignof是vs2013ctp中才支持的版本,如果没有该版本,用alignedment_of<T>::value代替 //typedef aligned_storage<sizeof(T), alignof(T)>::type AligendT; using AligendT = typename aligned_storage<sizeof(T), alignment_of<T>::value>::type; COptional(){} COptional(const T &t) { Create(t); } COptional(const COptional& other) { if (other.IsInit()) { Assign(other); } } ~COptional() { if (IsInit()) { Destroy(); } } const T & operator*() const { if (IsInit()) { return *((T *)(&m_Data)); } cout << "is not init!" << endl; } // 根据参数创建 template<typename ...ARGS> void Emplace(ARGS&& ...Args) { Destroy(); Create(forward<ARGS>(Args)...); } private: template <typename ...ARGS> void Create(ARGS&& ...Args) { new (&m_Data) T(forward<ARGS>(Args)...); // placement new 创建 m_bInit = true; } // 销毁缓冲区对象 void Destroy() { if (m_bInit) { m_bInit = false; ((T *)(&m_Data))->~T(); } } bool IsInit() const { return m_bInit; } void Assign(const COptional& other) { if (other.IsInit()) { Destroy(); new (&m_Data) (T)*((T*)(&other.m_Data)); m_bInit = true; } Destroy(); } private: AligendT m_Data; bool m_bInit = false; };
2.2. 惰性求值类lazy类实现
#pragma once #include<type_traits> #include<boost\optional.hpp> using namespace std; // 实现懒惰求值类lazy template<typename T> class CLazy { public: CLazy(){} template<typename FUN, typename ...ARG> CLazy(FUN &fun, ARG ...args) { std::cout << "参数个数:" << sizeof ...(args) << std::endl; m_fun = [&fun, args...]{return fun(args...); }; } T &Value() { if (!m_Value.is_initialized()) { m_Value = m_fun(); // 隐士转换 } return *m_Value; } bool IsCreated() const { return m_Value.is_initialized(); } private: std::function<T()> m_fun; boost::optional<T> m_Value; };
3. 测试
#include "stdio.h" #include "lazy.h" #include<iostream> using namespace std; #include "optionalex.h" int foo(int x) { cout << "函数名:" << __FUNCTION__ << endl; return 2 * x; } float fooadd(int x, int y, float z) { cout << "函数名:" << __FUNCTION__ << endl; return x + y+z; } template<typename FUN, typename ...ARG> CLazy<typename result_of<FUN(ARG...)>::type> lazy(FUN && fun, ARG && ...args) { return CLazy<typename result_of<FUN(ARG...)>::type>(forward<FUN>(fun), forward<ARG>(args)...); } struct test { int a; float b; test(int aa, float bb) :a(aa), b(bb){} friend ostream& operator<<(ostream& os, const test& other) { os << other.a << " " << other.b << endl; return os; } }; void main() { cout << "COptional类测试1,当对象没初始化:" << endl; COptional<int> op1; cout << "输出:" << *op1 << endl; cout << "COptional类测试2,int类型:" << endl; COptional<int> op2 = 99; cout << "输出:" << *op2 << endl; cout << "COptional类测试3,float类型:" << endl; COptional<float> op3 = 12.453; cout << "输出:" << *op3 << endl; cout << "COptional类测试4,struct类型:" << endl; COptional<test> op4 = test(8, 9.8); cout << "输出:" << *op4 << endl; cout << "lazy类测试:" << endl; CLazy<int> lazy1(foo, 2); cout << lazy1.Value() << endl; CLazy<float> lazy22(fooadd, 2, 4, 6.2); cout << lazy22.Value() << endl; cout << lazy([](int a, int b){return a + b; }, 10, 22).Value() << endl; }