C++11新特性之字节对齐、多参数模版、placement new
1. 内存对齐
#pragma pack(push, 1)
struct A
{
char a;
int b;
double c;
char d[];
};
#pragma pack(pop) #pragma pack(push, 2)
struct B
{
char a;
int b;
double c;
char d[];
};
#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) - ;
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 * 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 = ;
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(, 9.8);
cout << "输出:" << *op4 << endl; cout << "lazy类测试:" << endl;
CLazy<int> lazy1(foo, );
cout << lazy1.Value() << endl;
CLazy<float> lazy22(fooadd, , , 6.2);
cout << lazy22.Value() << endl;
cout << lazy([](int a, int b){return a + b; }, , ).Value() << endl;
}
C++11新特性之字节对齐、多参数模版、placement new的更多相关文章
- [转载] C++11新特性
C++11标准发布已有一段时间了, 维基百科上有对C++11新标准的变化和C++11新特性介绍的文章. 我是一名C++程序员,非常想了解一下C++11. 英文版的维基百科看起来非常费劲,而中文版维基百 ...
- C++11新特性总结 (一)
1. 概述 最近在看C++ Primer5 刚好看到一半,总结一下C++11里面确实加了很多新东西,如果没有任何了解,别说自己写了,看别人写的代码估计都会有些吃力.C++ Primer5是学习C++1 ...
- c++学习书籍推荐《深入理解C++11 C++11新特性解析与应用》下载
百度云及其他网盘下载地址:点我 编辑推荐 <深入理解C++11:C++11新特性解析与应用>编辑推荐:C++标准委员会成员和IBM XL编译器中国开发团队共同撰写,权威性毋庸置疑.系统.深 ...
- C++ 11学习和掌握 ——《深入理解C++ 11:C++11新特性解析和应用》读书笔记(一)
因为偶然的机会,在图书馆看到<深入理解C++ 11:C++11新特性解析和应用>这本书,大致扫下,受益匪浅,就果断借出来,对于其中的部分内容进行详读并亲自编程测试相关代码,也就有了整理写出 ...
- C++11新特性总结 (二)
1. 范围for语句 C++11 引入了一种更为简单的for语句,这种for语句可以很方便的遍历容器或其他序列的所有元素 vector<int> vec = {1,2,3,4,5,6}; ...
- C++ 11 新特性
C++11新特性: 1.auto 2.nullptr 3.for 4.lambda表达式 5.override ...
- 在C++98基础上学习C++11新特性
自己一直用的是C++98规范来编程,对于C++11只闻其名却没用过其特性.近期因为工作的需要,需要掌握C++11的一些特性,所以查阅了一些C++11资料.因为自己有C++98的基础,所以从C++98过 ...
- C++11新特性——range for
很多编程语言都有range for语法功能,自C++11起,终于将这个重要功能加入C++标准中.range for语句,可以方便的遍历给定序列中的每个元素并对其执行某种操作. 1.基本语法 for(d ...
- C++11新特性——大括号初始化
C++11之前,C++主要有以下几种初始化方式: //小括号初始化 string str("hello"); //等号初始化 string str="hello" ...
随机推荐
- url末尾的斜杠作用探秘
今天突然好奇,想区分www.abc.com/efg 和www.abc.com/efg/这两个网址的区别.即分析一下url末尾加个斜杠是否有特殊的效果. 找到网上的介绍: 当Web服务器接收到对某个末尾 ...
- Linux mount/unmount命令(6/16)
linux是一个优秀的开放源码的操作系统,可以运行在大到巨型小到掌上型各类计算机系统上,随着 linux系统的日渐成熟和稳定以及它开放源代码特有的优越性,linux在全世界得到了越来越广泛的应用.现在 ...
- CSS Id 和 Class选择器
CSS Id 和 Class选择器 如果你要在HTML元素中设置CSS样式,你需要在元素中设置"id" 和 "class"选择器. 一.id 选择器 id 选择 ...
- 谈谈对Canal(增量数据订阅与消费)的理解
概述 canal是阿里巴巴旗下的一款开源项目,纯Java开发.基于数据库增量日志解析,提供增量数据订阅&消费,目前主要支持了mysql(也支持mariaDB). 起源:早期,阿里巴巴B2B公司 ...
- Spring混合配置
Spring混合配置 一.在JavaConfig中引入其他配置 在JavaConfig中引入JavaConfig配置 使用@Import({OtherConfig1.class,OtherConfig ...
- sqoop数据导入到Hdfs 或者hive
用java代码调用shell脚本执行sqoop将hive表中数据导出到mysql http://www.cnblogs.com/xuyou551/p/7999773.html 用sqoop将mysql ...
- MySQL主从配置实现(同一台主机)
////////////////////MySQL主从(同一台主机)////////////////////// 1.安装配置MySQL参考之前步骤搭建MySQL服务为了做实验方便,我们在同一台机器上 ...
- C++ 进阶学习 ——模板
模板和重载类似,比重载更省事 通常有两种形式:函数模板和类模板: 函数模板针对仅参数类型不同的函数: 类模板针对仅数据成员和成员函数类型不同的类. 一个简单的函数模板 template <cla ...
- struts2提交文件时,出现页面重置又无法返回input现象,我没有解决这个问题
查看资料得知,是因为我使用的tomcat是8的原因,调整到6就可以了.但我没有改变Tomcat的版本,不知道该怎么解决这个问题.
- Spring获取bean的几种方式
工作中需要对一个原本加载属性文件的工具类修改成对数据库的操作当然,ado层已经写好,但是需要从Spring中获取bean,然而,工具类并没有交给Spring来管理,所以需要通过方法获取所需要的bean ...