【问题标题】:Syntax for dynamically allocating a 2D array of smart pointers动态分配二维智能指针数组的语法
【发布时间】:2013-03-07 11:26:45
【问题描述】:

我需要动态分配一个二维智能指针数组,但它的语法让我感到困惑。我需要它是动态的:

std::unique_ptr<someClass> myArray[size1][size2];

所以据我了解,我创建了一个指向类型指针的指针:

someClass** myArray; //actaully the type is std::unique_ptr<someClass> but I'll just keep it simple

然后分配它我做:

myArray* = new someClass*[size1];
for(int i = 0; i < size1; i++)
    myArray[i] = new someClass[size2];

但这并没有使用智能指针,这意味着我以后必须手动删除它,而且我不知道如何使这些指针成为智能指针;

类型是 std::unique_ptr 但是我需要一个指向该类型指针的指针,所以我尝试了:

std::unique_ptr<std::unique_ptr<std::unique_ptr<someClass>>> myArray;

但在此之后,我不知道如何分配它。有人可以帮帮我吗?

【问题讨论】:

  • 一维 vector&lt;unique_ptr&lt;T&gt;&gt; 应该是二维智能指针数组的良好替代品。
  • 另外,二维数组不是双指针。
  • 在 C++ 中,“X 的二维数组”拼写为 std::vector&lt;std::vector&lt;X&gt; &gt;
  • @n.m.需要注意的是,在这种情况下,内存不是连续的。这可能是也可能不是问题,但我通常会说“X 的二维数组是一个std::vector&lt;X&gt; 和一些(不是那么)聪明的索引”。

标签: c++ arrays memory-management multidimensional-array smart-pointers


【解决方案1】:

作为一个说明性示例,下面是可用于 C++ 现代的语法,用于使用智能指针 (unique_ptr) 和其他功能(例如 make_unique)创建和填充 2D int 数组(大小为 3 x 5)和move()

unique_ptr<unique_ptr<int[]>[]>     smartPtr2D;
unique_ptr<int[]>                   smartPtr1D;

int dataCounter = 0;

smartPtr2D = make_unique< unique_ptr<int[]>[] >(3);
for (int i = 0; i<3; i++)
{
    smartPtr1D = make_unique<int[]>(5);
    for (int j = 0; j<5; j++)
    {
        smartPtr1D[j] = dataCounter;
        dataCounter++;
    }
    smartPtr2D[i] = move(smartPtr1D);
}

【讨论】:

    【解决方案2】:

    我将向您展示如何具体解决您的问题,以及如何解决此类问题。

    一般来说,就像任何过于复杂的问题一样,尝试将其分解。在 C 和 C++ 中分解复杂类型声明的工具长期以来一直是“typedef”。以下是您对级联类型定义的处理方法,如您所拥有的:采用最内层的包装类型,即包装您的类的 unique_ptr,并为您想要包装的类型创建一个 typedef。然后,继续对该类型包装的类型执行相同的操作,直到您位于最外层的类型。

    这仅与您的问题相关,但我想提一下,因为您以后可能会遇到类似的问题,例如您现在使用模板时遇到的问题。从 C++11 开始,您还可以更方便地使用“using”子句为涉及模板参数的类型定义别名:http://en.cppreference.com/w/cpp/language/type_alias。如果您在这种情况下感兴趣或将来变得相关,请查看该链接!

    针对您的具体问题。函数“test_dynamic_2darray1”构建了一个二维 10x10 智能指针数组。运行此代码时,您应该会看到析构函数的 100 行输出,就在托管数组超出范围时。

    size_t destructor_count = 0;
    class MyClass {
        public:
        ~MyClass() {
            std::cout << "Destructor call #" << ++destructor_count << std::endl;
        }
    };
    
    typedef std::unique_ptr<MyClass[]> ManagedC;
    
    void test_dynamic_2darray1() {
        size_t dimension1 = 10, dimension2 = 10;
    
        auto managed_array = std::unique_ptr<ManagedC[]>(new ManagedC[dimension1]);
        for (size_t i = 0; i < dimension1; ++i)
            managed_array[i] = ManagedC(new MyClass[dimension2]);
    }
    

    比较一下这段代码,动态分配的类实例的析构函数不会被调用,你也看不到任何输出:

    void test_dynamic_2darray2() {
        size_t dimension1 = 10, dimension2 = 10;
    
        auto simple_array = new MyClass*[dimension1];
        for (size_t i = 0; i < dimension1; ++i)
            simple_array[i] = new MyClass[dimension2];
    }
    

    希望我能够回答您的问题! :) 如果你想让我详细说明一些事情,请告诉我!前几天我还写了一篇您可能感兴趣的相关博文:http://frankriesecodingblog.blogspot.com/2015/01/performance-of-dynamic-multi.html。我在这里发布它,因为它展示了多维动态数组的不同方法,并研究了使用向量向量的常用方法的性能。

    最后但同样重要的是,让我提一下您使用 int 来迭代数组。我希望这不会变成我的烦恼,但我看到这已经做了很多。您可能应该使用 size_t。为什么?例如,在我的 64 位机器上,“int”是 32 位的,但由 size_t 表示的地址是 64 位的。这种对 int 的误用是许多错误的原因,尤其是在将 32 位应用程序移植到 64 位机器时。如果您需要有符号类型,例如数组地址之间的偏移量,更好的用途可能是 ptrdiff_t。

    【讨论】:

    • 我尝试将您的解决方案应用于我的问题,但是当我尝试将我的二维双精度数组传递给函数进行处理时出现以下错误:error C2664: 'functionName' : cannot convert parameter 7 from 'std::unique_ptr&lt;_Ty&gt; *' to 'double **'。基本上我想创建二维双精度数组并分配内存,有一些初始化代码,然后它被传递给一个函数。如果函数抛出异常,我想使用智能指针来帮助清理。
    • 我想我需要做的是将dimension2(在您的示例中)设置为哑指针,但使用智能指针初始化它们并使用.get()将它们分配给二维数组?
    猜你喜欢
    • 2023-03-21
    • 2015-12-20
    • 2019-03-17
    • 2016-08-06
    • 1970-01-01
    • 1970-01-01
    • 2013-04-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多