关于C++中的POD型别

来源:互联网 发布:js数组元素移动位置 编辑:程序博客网 时间:2024/06/05 05:10

最近碰到笔试题中有关于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类型进行二进制拷贝后,数据都成功地迁移过来了。


POD是C++中一个很重要的概念,而且非常容易被忽视,其主要的用处是,POD对象(特别是数组)在进行复制的时候,不必调用对象的复制构造函数或者operator=,可以直接采用memcpy函数来提高效率。如何知道一个类变量或者结构体变量是否POD型别的呢? C++11中完全可以使用std::is_pod<> ,或者std::is_trivial<> 来检测,但是如果不支持C++11或者处于另外的考虑我们怎么办呢?,有时候我们自己也可以想个其他办法来检测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

0 0
原创粉丝点击