这是定义的行为吗?将数据存储为char数组

时间:2013-08-27 20:57:12

标签: c++ arrays memory

我正在玩动态大小内存池的想法,然后玩,我最终得到了一些我确定会失败但却没有的代码。这是代码:

#include <iostream>

using namespace std;

struct largeStruct
{
    largeStruct()
    {
        X = 123456789;
        Y = 987654321;
        str = "Hy! Here I am, a c string, out in the wild c++, the place where your pointers dangle and your friends play with your privates";
    }
    unsigned long long X;
    unsigned long long Y;
    char* str;
};

int main()
{
    void* ptr = new unsigned char[sizeof(largeStruct)];

    largeStruct a;
    *((largeStruct*)ptr) = a;

    cout << "Size of data: " << sizeof(largeStruct) << endl;
    cout << "Data: " << endl;
    cout << ((largeStruct*)ptr)->X << endl
         << ((largeStruct*)ptr)->Y << endl
         << ((largeStruct*)ptr)->str << endl
         << endl;

    delete[] ptr;
}

适用于我的电脑(Windows 8,MSVC Express 2012)。再加上一些,我认为,虽然是黑客,但它有一定道理。 内存中的数组是这样的:

===================================
... ||  a0  ||  a1  ||  a2   || ...
===================================

因此,当您尝试存储大于某个数组成员的值时,它会访问侧面的内存。因此,尝试存储3个块大小的值将起作用,并以此结束:

====================================
... || data  data  data  data || ...
====================================

那么,这是危险的,还是某种模糊无害的黑客?

1 个答案:

答案 0 :(得分:4)

  

§3.8...任何指向对象将要或所在的存储位置的指针   可以使用,但只能以有限的方式使用指针,就像指针的类型为void *一样,   定义明确。这样的指针可以被解除引用,但是所得到的左值可以仅以有限的方式使用,如下所述。如果出现以下情况,该程序的行为未定义:
   - 指针用作static_cast(5.2.9)的操作数(除非转换为void *,或者转换为void *,然后转换为char *或unsigned char *)

  

§3.9T类对象的对象表示是由T类对象占用的N个无符号char对象的序列,其中N等于sizeof(T)。

  

§3.10/ 10如果程序试图通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义:
   - char或unsigned char类型。

这些非常混乱,但似乎把你的指针位称称为合法。但是,您在一个尚未构造的非对象的对象上调用赋值运算符。最好的解决方法是这样的:

std::allocator<largeStruct> al;
largeStruct a;
unsigned char* ptr = new char[sizeof(largeStruct)]; //allocate memory
al.construct((largeStruct*)ptr, a); //call the copy constructor

....

al.destroy((largeStruct*)ptr); //destroy the object
delete[] ptr; //deallocate memory

std::allocator是所有C ++标准容器默认使用的标准分配器。 allocatedeallocate只需分别致电new char[]delete[]construct通过放置new来构造对象,destroy通过手动调用析构函数来破坏它。你可以在一行代码中自己做两件事,但使用分配器是更好的做法。

或者,不是构造默认构造的本地实例的副本,而是使用largeStruct

默认构建al.construct((largeStruct*)ptr);