【问题标题】:Better variant of getting the output dynamically-allocated array from the function?从函数中获取输出动态分配数组的更好变体?
【发布时间】:2010-04-05 09:34:13
【问题描述】:

这里有两种变体。第一:

int n = 42;

int* some_function(int* input)
{
    int* result = new int[n];
    // some code
    return result;
}

int main()
{
    int* input = new int[n];
    int* output = some_function(input);

    delete[] input;
    delete[] output;
    return 0;
}

这里函数返回内存,分配在函数内部。

第二种变体:

int n = 42;

void some_function(int* input, int* output)
{
    // some code
}

int main()
{
    int* input = new int[n];
    int* output = new int[n];
    some_function(input, output);

    delete[] input;
    delete[] output;
    return 0;
}

这里的内存是在函数外分配的。

现在我使用第一个变体。但我知道许多内置的 c++ 函数使用第二种变体。 第一个变体更舒服(在我看来)。但是第二个也有一些优点(你在同一个块中分配和删除内存)。

也许这是一个愚蠢的问题,但哪种变体更好,为什么?

【问题讨论】:

    标签: c++ pointers memory-management


    【解决方案1】:

    第三种变体

    const int n = 42; 
    
    template<class It1, class It2>
    void some_function(It1 First, It1 Last, It2 output) 
    { 
        // some code 
    } 
    
    void main() 
    { 
        std::vector<int> input(n);
        std::vector<int> output(n);
        some_function(input.begin(), input.end(), output.begin()); 
    
    } 
    

    【讨论】:

      【解决方案2】:

      我认为第二个变体更好,因为你有“对指针的平衡责任”。这使代码更具可读性,因为您可以看到分配和释放内存的位置。
      如果你想使用第一个变体,我建议你做双重功能some_function_free()。至于malloc/freenew/deletenew[]/delete[]等。即使它会很简单delete[],通过使用它你会节省时间想改变你分配内存的方式。

      【讨论】:

        【解决方案3】:

        这两种变体都不是首选的 C++ 风格,尤其是存在异常时。如果在某处抛出异常(在output 的分配中或some_function 的主体中),您的一个或两个动态分配的数组将泄漏内存。首选方法是使用资源分配即初始化 (RAII) 概念。安全的 C++ 代码使用对象来获取资源。他们的析构函数释放了这些资源。当堆栈从异常中展开时,此时获取的所有资源都会被安全释放。

        对于动态分配的数组,这意味着std::vector。如果它不会对您的性能产​​生不利影响(如果您担心,请对其进行分析),您甚至可以按值返回一个。

        // don't need the global variable anymore
        std::vector<int> some_function(std::vector<int> &input)
        {
            std::vector<int> result;
            // do something
            return result;
        }
        
        int main()  // main returns int, not void
        {
            std::vector<int> input;
            // insert some values
            std::vector<int> output = some_function(input);
            return 0;
        }
        

        不再需要担心谁负责分配和释放内存。您的代码变得更清晰且异常安全。

        【讨论】:

          【解决方案4】:

          一般来说,如果可行的话,函数最好不要堆分配和返回对象。它会产生所有权问题,并使接口复杂化(调用者必须知道如何管理返回对象的生命周期)。它还给内存分配器带来了更大的压力,这反过来又会造成线程争用,并剥夺了调用者通过更明智地为事物分配空间来避免这种成本的机会。

          【讨论】:

            【解决方案5】:

            第二个的另一个好处是它不需要堆分配。您只能使用堆栈分配的内存调用代码:

            int main()
            {
                int input[10];
                int output[10];
            
                some_function(input, output);
            }
            

            【讨论】:

              猜你喜欢
              • 2018-09-25
              • 1970-01-01
              • 1970-01-01
              • 2013-09-05
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-09-27
              • 2018-02-28
              相关资源
              最近更新 更多