最近碰到笔试题中有关于POD型别的问题,看了好多博客对此还是没有理解透彻,总结在此便于日后学习.
POD全称Plain Old Data。通俗的讲,一个类或结构体通过二进制拷贝后还能保持其数据不变,那么它就是一个POD类型。
平凡的定义:
1. 有平凡的构造函数;
2. 有平凡的拷贝构造函数;
3. 有平凡的移动构造函数;
4. 有平凡的拷贝赋值运算符;
5. 有平凡的移动赋值运算符;
6. 有平凡的析构函数;
7. 不能包含虚函数;
8. 不能包含虚基类。
#include <iostream>
using namespace std;
class A { A(){} };
class B { B(B&){} };
class C { C(C&&){} };
class D { D operator=(D&){} };
class E { E operator=(E&&){} };
class F { ~F(){} };
class G { virtual void foo() = 0; };
class H : G {};
class I {};
int main(int argc, char* argv[])
{
std::cout << boolalpha;
std::cout << std::is_trivial<A>::value << std::endl; // 有不平凡的构造函数
std::cout << std::is_trivial<B>::value << std::endl; // 有不平凡的拷贝构造函数
std::cout << std::is_trivial<C>::value << std::endl; // 有不平凡的拷贝赋值运算符
std::cout << std::is_trivial<D>::value << std::endl; // 有不平凡的拷贝赋值运算符
std::cout << std::is_trivial<E>::value << std::endl; // 有不平凡的移动赋值运算符
std::cout << std::is_trivial<F>::value << std::endl; // 有不平凡的析构函数
std::cout << std::is_trivial<G>::value << std::endl; // 有虚函数
std::cout << std::is_trivial<H>::value << std::endl; // 有虚基类
std::cout << std::is_trivial<I>::value << std::endl; // 平凡的类
return 0;
}
标准布局的定义:
1. 所有非静态成员有相同的访问权限;
2. 继承树中最多只能有一个类有非静态数据成员;
3. 子类的第一个非静态成员不可以是基类类型;
4. 没有虚函数;
5. 没有虚基类;
6. 所有非静态成员都符合标准布局类型。
#include <iostream>
using namespace std;
class A
{
private:
int a;
public:
int b;
};
class B1
{
static int x1;
};
class B2
{
int x2;
};
class B : B1, B2
{
int x;
};
class C1 {};
class C : C1
{
C1 c;
};
class D { virtual void foo() = 0; };
class E : D {};
class F { A x; };
int main(int argc, char* argv[])
{
std::cout << boolalpha;
std::cout << std::is_standard_layout<A>::value << std::endl; // 违反定义1。成员a和b具有不同的访问权限
std::cout << std::is_standard_layout<B>::value << std::endl; // 违反定义2。继承树有两个(含)以上的类有非静态成员
std::cout << std::is_standard_layout<C>::value << std::endl; // 违反定义3。第一个非静态成员是基类类型
std::cout << std::is_standard_layout<D>::value << std::endl; // 违反定义4。有虚函数
std::cout << std::is_standard_layout<E>::value << std::endl; // 违反定义5。有虚基类
std::cout << std::is_standard_layout<F>::value << std::endl; // 违反定义6。非静态成员x不符合标准布局类型
return 0;
}
当一个数据类型满足了“平凡的定义”和“标准布局”,我们就认为它是一个POD数据——可以通过std::is_pod来判断一个类型是否为POD类型。
如文章开头说的,一个POD类型是可以进行二进制拷贝的,看看下面的例子——
class A
{
private:
int a;
public:
int b;
};
class B1
{
static int x1;
};
class B2
{
int x2;
};
class B : B1, B2
{
int x;
};
class C1 {};
class C : C1
{
C1 c;
};
class D { virtual void foo() = 0; };
class E : D {};
class F { A x; };
int main(int argc, char* argv[])
{
std::cout << boolalpha;
std::cout << std::is_standard_layout<A>::value << std::endl; // 违反定义1。成员a和b具有不同的访问权限
std::cout << std::is_standard_layout<B>::value << std::endl; // 违反定义2。继承树有两个(含)以上的类有非静态成员
std::cout << std::is_standard_layout<C>::value << std::endl; // 违反定义3。第一个非静态成员是基类类型
std::cout << std::is_standard_layout<D>::value << std::endl; // 违反定义4。有虚函数
std::cout << std::is_standard_layout<E>::value << std::endl; // 违反定义5。有虚基类
std::cout << std::is_standard_layout<F>::value << std::endl; // 违反定义6。非静态成员x不符合标准布局类型
return 0;
}
可以看到,对一个POD类型进行二进制拷贝后,数据都成功地迁移过来了。
在http://blog.csdn.net/hustleverpi/article/details/5671979中作者提到了另一种方法鉴定是否为POD型别:
今天看到了一个方法,让我眼前一亮,它能够编译期确定一个型别是否为POD型别。但是,却不能利用该特性进行型别萃取,只能判断某一型别是否为POD型别,如果不是,编译器报错。方法如下:
template<class T>
struct must_be_pod
{
union
{
T noname;
};
};
将一个类作为模板形参传入,如果其是POD型别,则可以放入union中,否则,不是POD类型。这里其实,是将POD型别等价于可以放入union中的对象。C++中,可以放入union中的对象,是其本身以及其所有的成员变量都没有默认构造函数的对象。
但是上面的例子仅仅适用于非C++11中,在C++03中,并非任意的类型都能做为union的成员。比方说,带有non-trivial 构造函数的类型就不能是union的成员。在新的标准里,移除了所有对union的使用限制,除了其成员仍然不能是引用类型。这一改变使得union更强大,更有用,也易于使用。例如,
struct point
{
point() {}
point(int x, int y): x_(x), y_(y) {}
int x_, y_;
};
union
{
int z;
double w;
point p; // 不合法的C++; point有一non-trivial建構式
// 合法的C++11
};
那么C++11中的一些类型是否是POD型别呢?测试如下:
int main(void)
{
cout << "int:" << endl;
cout << "is_trivial: " << is_trivial<int>::value << endl;
cout << "is_standard_layout: " << is_standard_layout<int>::value << endl;
cout << "is_pod: " << is_pod<int>::value << endl << endl;
cout << "string:" << endl;
cout << "is_trivial: " << is_trivial<string>::value << endl;
cout << "is_standard_layout: " << is_standard_layout<string>::value << endl;
cout << "is_pod: " << is_pod<string>::value << endl;
cout << "sizeof(string): " << sizeof(string) << endl << endl;
cout << "array<int>:" << endl;
cout << "is_trivial: " << is_trivial<array<int, 5>>::value << endl;
cout << "is_standard_layout: " << is_standard_layout<array<int, 5>>::value << endl;
cout << "is_pod: " << is_pod<array<int, 5>>::value << endl << endl;;
cout << "array<string>:" << endl;
cout << "is_trivial: " << is_trivial<array<string, 5>>::value << endl;
cout << "is_standard_layout: " << is_standard_layout<array<string, 5>>::value << endl;
cout << "is_pod: " << is_pod<array<string, 5>>::value << endl << endl;
cout << "pair<int, int>:" << endl;
cout << "is_trivial: " << is_trivial<pair<int, int>>::value << endl;
cout << "is_standard_layout: " << is_standard_layout<pair<int, int>>::value << endl;
cout << "is_pod: " << is_pod<pair<int, int>>::value << endl;;
cout << "sizeof(pair<int, int>): " << sizeof(pair<int,int>) << endl << endl;
cout << "pair<string, string>:" << endl;
cout << "is_trivial: " << is_trivial<pair<string, string>>::value << endl;
cout << "is_standard_layout: " << is_standard_layout<pair<string, string>>::value << endl;
cout << "is_pod: " << is_pod<pair<string, string>>::value << endl;
cout << "sizeof(pair<string, string>): " << sizeof(pair<string, string>) << endl << endl;
cout << "vector<int>:" << endl;
cout << "is_trivial: " << is_trivial<vector<int>>::value << endl;
cout << "is_standard_layout: " << is_standard_layout<vector<int>>::value << endl;
cout << "is_pod: " << is_pod<vector<int>>::value << endl;;
cout << "sizeof(vector<int>): " << sizeof(vector<int>) << endl << endl;
cout << "vector<string>:" << endl;
cout << "is_trivial: " << is_trivial<vector<string>>::value << endl;
cout << "is_standard_layout: " << is_standard_layout<vector<string>>::value << endl;
cout << "is_pod: " << is_pod<vector<string>>::value << endl;
cout << "sizeof(vector<string>): " << sizeof(vector<string>) << endl << endl;
cout << "deque<int>:" << endl;
cout << "is_trivial: " << is_trivial<deque<int>>::value << endl;
cout << "is_standard_layout: " << is_standard_layout<deque<int>>::value << endl;
cout << "is_pod: " << is_pod<deque<int>>::value << endl;;
cout << "sizeof(deque<int>): " << sizeof(deque<int>) << endl << endl;
cout << "deque<string>:" << endl;
cout << "is_trivial: " << is_trivial<deque<string>>::value << endl;
cout << "is_standard_layout: " << is_standard_layout<deque<string>>::value << endl;
cout << "is_pod: " << is_pod<deque<string>>::value << endl;
cout << "sizeof(deque<string>): " << sizeof(deque<string>) << endl << endl;
cout << "list<int>:" << endl;
cout << "is_trivial: " << is_trivial<list<int>>::value << endl;
cout << "is_standard_layout: " << is_standard_layout<list<int>>::value << endl;
cout << "is_pod: " << is_pod<list<int>>::value << endl;
cout << "sizeof(list<int>): " << sizeof(list<int>) << endl << endl;
cout << "list<string>:" << endl;
cout << "is_trivial: " << is_trivial<list<string>>::value << endl;
cout << "is_standard_layout: " << is_standard_layout<list<string>>::value << endl;
cout << "is_pod: " << is_pod<list<string>>::value << endl;
cout << "sizeof(list<string>): " << sizeof(list<string>) << endl << endl;
cout << "vector<list<int>>:" << endl;
cout << "is_trivial: " << is_trivial<vector<list<int>>>::value << endl;
cout << "is_standard_layout: " << is_standard_layout<vector<list<int>>>::value << endl;
cout << "is_pod: " << is_pod<vector<list<int>>>::value << endl;
cout << "sizeof(vector<list<int>>): " << sizeof(vector<list<int>>) << endl << endl;
cout << "vector<list<string>>:" << endl;
cout << "is_trivial: " << is_trivial<vector<list<string>>>::value << endl;
cout << "is_standard_layout: " << is_standard_layout<vector<list<string>>>::value << endl;
cout << "is_pod: " << is_pod<vector<list<string>>>::value << endl;
cout << "sizeof(vector<list<string>>): " << sizeof(vector<list<string>>) << endl << endl;
cout << "set<int>:" << endl;
cout << "is_trivial: " << is_trivial<set<int>>::value << endl;
cout << "is_standard_layout: " << is_standard_layout<set<int>>::value << endl;
cout << "is_pod: " << is_pod<set<int>>::value << endl;
cout << "sizeof(set<int>): " << sizeof(set<int>) << endl << endl;
cout << "set<string>:" << endl;
cout << "is_trivial: " << is_trivial<set<string>>::value << endl;
cout << "is_standard_layout: " << is_standard_layout<set<string>>::value << endl;
cout << "is_pod: " << is_pod<set<string>>::value << endl;
cout << "sizeof(set<string>): " << sizeof(set<string>) << endl << endl;
cout << "map<int, int>:" << endl;
cout << "is_trivial: " << is_trivial<map<int, int>>::value << endl;
cout << "is_standard_layout: " << is_standard_layout<map<int, int>>::value << endl;
cout << "is_pod: " << is_pod<map<int, int>>::value << endl;
cout << "sizeof(map<int, int>): " << sizeof(map<int, int>) << endl << endl;
cout << "map<string, string>:" << endl;
cout << "is_trivial: " << is_trivial<map<string, string>>::value << endl;
cout << "is_standard_layout: " << is_standard_layout<map<string, string>>::value << endl;
cout << "is_pod: " << is_pod<map<string, string>>::value << endl;
cout << "sizeof(map<string, string>): " << sizeof(map<string, string>) << endl << endl;
cout << "unordered_set<int>:" << endl;
cout << "is_trivial: " << is_trivial<unordered_set<int>>::value << endl;
cout << "is_standard_layout: " << is_standard_layout<unordered_set<int>>::value << endl;
cout << "is_pod: " << is_pod<unordered_set<int>>::value << endl;
cout << "sizeof(unorder_set<int>): " << sizeof(unordered_set<int>) << endl << endl;
cout << "unordered_set<string>:" << endl;
cout << "is_trivial: " << is_trivial<unordered_set<string>>::value << endl;
cout << "is_standard_layout: " << is_standard_layout<unordered_set<string>>::value << endl;
cout << "is_pod: " << is_pod<unordered_set<string>>::value << endl;
cout << "sizeof(unorder_set<string>): " << sizeof(unordered_set<string>) << endl << endl;
cout << "unordered_map<int, int>:" << endl;
cout << "is_trivial: " << is_trivial<unordered_map<int, int>>::value << endl;
cout << "is_standard_layout: " << is_standard_layout<unordered_map<int, int>>::value << endl;
cout << "is_pod: " << is_pod<unordered_map<int, int>>::value << endl;
cout << "sizeof(unorder_map<int, int>): " << sizeof(unordered_map<int, int>) << endl << endl;
cout << "unordered_map<string, string>:" << endl;
cout << "is_trivial: " << is_trivial<unordered_map<string, string>>::value << endl;
cout << "is_standard_layout: " << is_standard_layout<unordered_map<string, string>>::value << endl;
cout << "is_pod: " << is_pod<unordered_map<string, string>>::value << endl;
cout << "sizeof(unorder_map<string, string>): " << sizeof(unordered_map<string, string>) << endl << endl;
cout << "shared_ptr<int>:" << endl;
cout << "is_trivial: " << is_trivial<shared_ptr<int>>::value << endl;
cout << "is_standard_layout: " << is_standard_layout<shared_ptr<int>>::value << endl;
cout << "is_pod: " << is_pod<shared_ptr<int>>::value << endl;
cout << "sizeof(shared_ptr<int>): " << sizeof(shared_ptr<int>) << endl << endl;
cout << "unique_ptr<int>:" << endl;
cout << "is_trivial: " << is_trivial<unique_ptr<int>>::value << endl;
cout << "is_standard_layout: " << is_standard_layout<unique_ptr<int>>::value << endl;
cout << "is_pod: " << is_pod<unique_ptr<int>>::value << endl;
cout << "sizeof(unique_ptr<int>): " << sizeof(unique_ptr<int>) << endl << endl;
return 0;
}
程序输出:
int: is_trivial: 1 is_standard_layout: 1 is_pod: 1
string: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(string): 4
array<int>: is_trivial: 1 is_standard_layout: 1 is_pod: 1
array<string>: is_trivial: 0 is_standard_layout: 1 is_pod: 0
pair<int, int>: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(pair<int, int>): 8
pair<string, string>: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(pair<string, string>): 8
vector<int>: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(vector<int>): 12
vector<string>: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(vector<string>): 12
deque<int>: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(deque<int>): 40
deque<string>: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(deque<string>): 40
list<int>: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(list<int>): 8
list<string>: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(list<string>): 8
vector<list<int>>: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(vector<list<int>>): 12
vector<list<string>>: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(vector<list<string>>): 12
set<int>: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(set<int>): 24
set<string>: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(set<string>): 24
map<int, int>: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(map<int, int>): 24
map<string, string>: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(map<string, string>): 24
unordered_set<int>: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(unorder_set<int>): 24
unordered_set<string>: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(unorder_set<string>): 24
unordered_map<int, int>: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(unorder_map<int, int>): 24
unordered_map<string, string>: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(unorder_map<string, string>): 24
shared_ptr<int>: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(shared_ptr<int>): 8
unique_ptr<int>: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(unique_ptr<int>): 4
结论:内置类型(如: int, float),array<int>是POD类型
POD类型是递归的,array<string>就不是POD类型,因为string不是
所有测试类型包括:pair(tuple), vector, list, deque, set, map, unordered_set, unordered_map, shared_ptr, unique_ptr
都满足 is_standard_layout但是不满足is_trivial,因此也不满足is_pod类型。
unique_ptr具有和普通指针一样大小,大多数时候应该使用它(当然还有其它原因: 如unique性能更好等等),而不是shared_ptr。
测试参考: http://www.cnblogs.com/hancm/p/3665998.html