在C#和C++中返回一个二维数组

4
我正在编写一个返回2D数组的函数。这让我想到了在C#(有垃圾回收)和C++(没有垃圾回收)中的影响。
为什么两者都需要呢?你可能会问:我现在在Windows平台上使用C#编写它,但几个月后我将在使用C++的嵌入式设备上实现我的算法。
所以基本上我有一个2D数组,比如说table,并通过一个函数将其分配给了返回值。我的问题是:原始存储原始table的内存块会发生什么?
现在来看代码:
在C#中:
    using System;

    public class Test
    {
        public static void Main()
        {
            int[,] table= new int [10,10];  //Here some memory is separated for table 
            int[,] table= createTable(10,10); //Here the return value of createTable is assigned to the original value 

//WHAT HAPPENED TO THE ORIGINAL MEMORY THAT table HAD?

            printTable(table,10,10); //disregard this. Not that important
        }

        public static int[,] createTable(int rows, int columns)
        {
            int[,] t = new int[rows,columns];
            for(int i=0;i<rows;i++)
              for(int j=0;j<columns;j++)
                 t[i,j]=(i+j);

             return t;    
        }

        public static void printTable(int[,]t, int rows, int columns)
        {
            for(int i=0;i<rows;i++)
              for(int j=0;j<columns;j++)
                Console.WriteLine(t[i,j]);

             foreach( var im in t)
               Console.WriteLine(im);
        }
    }

(请不要告诉我第一个新的int是不必要的等等。对于这个问题来说,它是必须的,可以通过调用两次createTable来替换它)

我猜想在C#中,垃圾收集器会处理这个问题,所以我不需要担心?


现在进入C++

#include <cstdio>
#include <cstdlib>


int** createTable(int rows, int columns){
    int** table = new int*[rows];
    for(int i = 0; i < rows; i++) {
        table[i] = new int[columns]; 
        for(int j = 0; j < columns; j++){ table[i][j] = (i+j); }// sample set value;    
    }
    return table;
}
void freeTable(int** table, int rows){
    if(table){
        for(int i = 0; i < rows; i++){ if(table[i]){ delete[] table[i]; } }
        delete[] table;    
    }
}
void printTable(int** table, int rows, int columns){
    for(int i = 0; i < rows; i++){
        for(int j = 0; j < columns; j++){
            printf("(%d,%d) -> %d\n", i, j, table[i][j]);
        }    
    }
}
int main(int argc, char** argv){

    int** table = createTable(5, 5);
    table = createTable(10,10);
    printTable(table, 10, 10);
    freeTable(table, 10);
    return 0;
}
原本持有的内存发生了什么情况 (5x5)。当table被分配为10x10的表时,是否会造成内存泄漏?如何避免这种情况?

请记住,指针不是数组,指向指针的指针也不是“二维数组”。在C++中无法返回数组,这是语言的限制。 - juanchopanza
这看起来更像是C风格的方法,而不是C ++。也许在C ++中使用智能指针可以解决您的问题。 - macroland
2
使用RAII对象(如vector<vector<int>>)来避免担心内存释放问题。 - Jarod42
createTable函数本身已经存在潜在的泄漏问题,因为每个new操作都可能会抛出异常。请不要试图根据某些类似语法在另一种语言中编写C++代码,这将导致非常糟糕的结果。如果想要编写好的C++代码,请系统地学习这门语言并阅读优秀的书籍。 - Baum mit Augen
我建议如果你要分配内存,使用std::make_shared或std::make_unique,并学习它们的语义。然后,除非你粗心(shared_ptr中的循环引用),否则你再也不会有"泄漏"的问题了。 - Robinson
1
顺便提一下,如果这个程序旨在实现矩阵而不是数组的数组,请不要使用嵌套向量,而是编写一个适当的矩阵类,以正确保证矩阵的不变性,如矩阵的矩形形式。还有许多好的和免费的矩阵实现可在库中轻松获得,例如 eigen。 - Baum mit Augen
3个回答

2

对于 C++ 部分,是的,你会创建内存泄漏。你需要调用 freeTable

int** table = createTable(5, 5);
freeTable(table, 5);
table = createTable(10,10);
printTable(table, 10, 10);
freeTable(table, 10);

最好使用 RAII 对象作为 vector<vector<int>>(或专门的类 Matrix)来避免担心内存释放问题(你还可以在类中添加大小信息)。

因此,代码将变得简单:

auto table = createTable(5, 5);
table = createTable(10,10);
printTable(table);

即使你完全不关心性能,vector<vector<int>>对于矩阵来说也是一个很差的数据结构。它甚至不能保证所有行具有相同的长度。 - Baum mit Augen
为什么使用向量可以避免内存泄漏的产生? - KansaiRobot
1
@KansaiRobot:因为向量是一个Raii对象,可以正确地释放内部内存。 - Jarod42
@ BaummitAugen 谢谢。你有没有关于高级C++的好书推荐?我已经阅读了许多C++基础知识并为我的嵌入式平台编写了工作代码,但我通常会思考这些基础知识中未包含的内容。 - KansaiRobot
@KansaiRobot 这里是我们的标准列表。 - Baum mit Augen
显示剩余4条评论

2
在C#中,垃圾回收器会处理不再可访问的内存。
我使用Debian Buster上的gcc(版本:(Debian 6.4.0-1)6.4.0 20170704)编译了您的C ++程序。
非常有用的检查各种内存问题的工具valgrind,通过valgrind --leak-check=full ./test命令输出以下结果:
Memcheck, a memory error detector
Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
Command: ./test

[... program output ...]

HEAP SUMMARY:
    in use at exit: 140 bytes in 6 blocks
  total heap usage: 19 allocs, 13 frees, 74,348 bytes allocated

140 (40 direct, 100 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 2
   at 0x4C2C97F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
   by 0x10883E: createTable(int, int) (in /home/user/code/test/test)
   by 0x108A26: main (in /home/user/code/test/test)

LEAK SUMMARY:
   definitely lost: 40 bytes in 1 blocks
   indirectly lost: 100 bytes in 5 blocks
     possibly lost: 0 bytes in 0 blocks
   still reachable: 0 bytes in 0 blocks
        suppressed: 0 bytes in 0 blocks

For counts of detected and suppressed errors, rerun with: -v
ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

如您所见,您的内存正在被损失。要解决这个问题,您可以先调用freeTable()函数然后再重新分配指针,或者使用智能指针来回避这个问题。


0

在这一行:

//WHAT HAPPENED TO THE ORIGINAL MEMORY THAT table HAD?

你正在覆盖它的引用。由于原始表不再被引用,垃圾回收器一旦运行就会清理已使用的空间。

很抱歉,我无法回答你关于C++的问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接