0

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

#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)。虽然在其中添加了更多内容,但我认为,虽然是 hack,但它是有道理的。内存中的数组是这样的:

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

因此,当您尝试存储大于数组成员之一的值时,它会访问侧面的内存。因此,尝试存储 3 个块大小的值将起作用,并最终如下所示:

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

那么,这是危险的,还是某种晦涩难懂的无害黑客?

4

1 回答 1

4

§ 3.8 ...可以使用任何指向对象将位于或所在的存储位置的指针,但只能以有限的方式使用...使用指针,就好像指针是void *类型一样,是明确定义的。这样的指针可能会被取消引用,但生成的左值只能以有限的方式使用,如下所述。程序在以下情况下具有未定义的行为:
— 指针用作 static_cast (5.2.9) 的操作数(转换为 void* 或 void* 并随后转换为 char* 或 unsigned char* 时除外)

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

§ 3.10/10 如果程序试图通过非下列类型之一的泛左值访问对象的存储值,则行为未定义:
— 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++ 标准容器默认使用的标准分配器。allocate并分别deallocate调用new char[]delete[]construct通过placement new 就地构造对象,并destroy通过手动调用析构函数将其析构。您可以在一行代码中自己完成这两项工作,但使用分配器是更好的做法。

largeStruct或者,不是构造默认构造的本地实例的副本,而是简单地使用默认构造al.construct((largeStruct*)ptr);

于 2013-08-27T21:06:05.167 回答