为什么析构函数不接受C ++中的参数?

时间:2017-07-04 15:35:45

标签: c++ memory-management

最近,我遇到了一个示例,我的析构函数需要参数。

我正在开发一个内部管理内存的C包,并跟踪分配和释放自己的参数。我不想打破那个。

我编写了一个C代码,它初始化了我自己的数据结构,并在最后释放它们。当我决定迁移到C ++时,我意识到分配数据结构并释放它们应该放在构造函数和析构函数中。所以我将这些函数更改为构造函数和析构函数。 我现在的问题是我需要使用一个参数传递给析构函数以释放分配的数据;该参数不在我自己的代码中,而且是C,我不想搞砸。

我的问题有两个:

为什么C ++决定不首先接受析构函数中的参数? 和 我有什么选择? (我可以保存一个指向该参数的指针,或者以某种方式在我的析构函数中调用该函数,但它似乎不是C ++编程的好习惯)

更新:添加一些代码 这是我想象中的课程:

class paru_symbolic/* paru_symbolic*/
{
    public:
        paru_symbolic ( cholmod_sparse *A, cholmod_common *cc ); // constructor
        ~paru_symbolic (cholmod_common *cc ); // destructor

        // -------------------------------------------------------------------------
        // row-form of the input matrix and its permutations
        // -----------------------------------------------------------------------
              //--- other stuff
                     ...
};

这是我当前的C构造函数:

#include "Parallel_LU.hpp"
paru_symbolic *paru_sym_analyse
(
 // inputs, not modified
   cholmod_sparse *A,
 // workspace and parameters
   cholmod_common *cc ){   

    DEBUGLEVEL(0);
...
   aParent = (Int*) paru_alloc (m+nf, sizeof(Int),cc);

...
}

和析构函数:

void paru_freesym (paru_symbolic **LUsym_handle,
            // workspace and parameters
    cholmod_common *cc
){
    DEBUGLEVEL (0);
    if (LUsym_handle == NULL || *LUsym_handle == NULL){
        // nothing to do; caller probably ran out of memory
        return;
    }

    paru_symbolic *LUsym;
    LUsym = *LUsym_handle;

    Int m, n, anz, nf, rjsize; 
...
    cholmod_l_free (m+nf, sizeof (Int), LUsym->aParent, cc);

...
    cholmod_l_free (1, sizeof (paru_symbolic), LUsym, cc);

   *LUsym_handle = NULL;
}

在SuiteSparse包中使用参数cc来跟踪分配和释放数据。它已经在SuiteSparse包中使用,是一个用于跟踪内存的有用工具。 有些人提到谁想要将参数传递给析构函数。这是一个公平的观点,但我们可以在构造函数中使用与默认值相同的参数。

3 个答案:

答案 0 :(得分:14)

析构函数中的参数没有意义,因为当对象超出范围时会自动调用析构函数。你怎么能把参数传递给那个?

{ 
   Foo x;
} // `~Foo()` is automatically called here

您可能想要的是将资源存储在您的班级中。这是一个动态分配指针的不切实际的例子:

struct RAIIPointer
{
    Foo* ptr;

    // Initialize the resource
    RAIIPointer() : ptr{new Foo{/*...*/}}
    {
    }

    RAIIPointer(const RAIIPointer&) = delete;
    RAIIPointer& operator=(const RAIIPointer&) = delete;

    RAIIPointer(RAIIPointer&&) { /* implement appropriately */ }
    RAIIPointer& operator=(RAIIPointer&&) { /* implement appropriately */ }

    // Release the resource
    ~RAIIPointer() 
    {
        delete ptr;
    }
};

请注意,在实际场景中,您将使用std::unique_ptr,如果您要实现自己的RAII资源类,则需要实现正确的复制/移动操作。

答案 1 :(得分:2)

@Vittorio的答案有一般方法。我只是根据您添加的示例代码进行定制。

您提出问题的方式如下:

  1. 您使用实用程序类型cholmod_common为您的类型执行一些有用的工作。
  2. 该类型的实例可以传递给您创建的多个paru_symbolic个对象。
  3. paru_symbolic没有一个单独的实例拥有它,但它们在生命的开始和结束时都依赖它。它必须与所有这些对象保持相同的持续时间。
  4. 那对我{{}}尖叫。

    class paru_symbolic
    {
        std::shared_ptr<cholmod_common> _cc;
        public:
            paru_symbolic ( cholmod_sparse *A, std::shared_ptr<cholmod_common> cc)
             : _cc(cc) {
               // constructor
             } 
            ~paru_symbolic () {
              // use _cc , it's guaranteed to live until the closing brace at the least.
            }
    };
    

    那就是它。现在共享所有权。取决于cholmod_common实例的最后一个对象将是清理它的那个,而不需要你做额外的工作。

答案 2 :(得分:0)

在C ++中,这类事情是通过allocator完成的,另请参阅std::allocator。因此,您可以使用cholmod_common*数据成员创建自己的分配器。

或者,您可以使用 deleter 参数通过智能指针进行内存管理。例如

class foo
{
  struct bar_deleter {
    cholmod_common *cc;
    bar_deleter(cholmod_common *c) : cc(c) {}
    void destroy(bar*) { cc->free(bar); }
  };
  std::unique_ptr<bar,bar_deleter> data;
public:
  foo(some_type const&input, cholmod_common *cc)
    : data(cc->create<bar>(input), bar_deleter(cc)) {}
};

当然,这也会保留cholmod_common*数据。

名称&#34; cholmod_common&#34;表明这是一个 common 资源,即在任何给定时间只有一个cholmod_common对象。 Iff 就是这样,那么你可以使用无状态分配器,它将公共资源保存为静态数据成员(或通过singleton获得它。)

相关问题