【问题标题】:Is it possible to use a C++ smart pointers together with C's malloc?是否可以将 C++ 智能指针与 C 的 malloc 一起使用?
【发布时间】:2011-03-29 11:56:25
【问题描述】:

我的一些代码仍然使用malloc 而不是new。原因是我害怕使用new,因为它会抛出异常,而不是返回NULL,我可以轻松检查。将每个对new 的调用都封装在try{}catch(){} 中看起来也不是那么好。而当使用malloc 时,我可以使用if (!new_mem) { /* handle error */ }

因此我有一个问题。我可以将智能指针与malloc 一起使用吗?

类似:

SmartPointer<Type> smarty = malloc(sizeof(Type));

类似的东西。

这可能吗?

谢谢,博达·赛多。

【问题讨论】:

  • 如果你想让 new 现在抛出一个异常并且只返回 NULL,你可以使用:Type* bla = new (std::nothrow) Type();。我认为使用 std::nothrow 比使用 malloc 更好,因为后者不调用构造函数。
  • 你打算在错误处理代码中做什么来补偿没有获得内存?通常测试是如果分配工作那么做工作。如果失败并返回错误代码退出(这是一种将控制权传回堆栈的复杂方式)。

标签: c++ malloc new-operator smart-pointers


【解决方案1】:

这取决于 SmartPointer 在销毁时的作用。如果您可以将free 指定为释放器,则可以使用。例如, boost::shared_ptr 允许您指定删除器。

我没有足够注意你想要这个的原因。我同意其他答案,即使用 nothrow new 是一个更好的主意。

【讨论】:

    【解决方案2】:

    可以将 malloc 与智能指针一起使用(您必须将返回值转换为目标指针类型,并提供自定义释放器)。但更好的选择是使用nothrow 版本的new 运算符。

    http://www.cplusplus.com/reference/std/new/nothrow/

    【讨论】:

      【解决方案3】:

      您可以在 new 运算符中使用 nothrow 关键字,这将返回 NULL 而不是引发异常。详情见以下链接: http://www.cplusplus.com/reference/std/new/nothrow/

      【讨论】:

      • 使用nothrow 是一种常见的做法吗? (因为我自己并没有在实际实践中亲眼看到过 nothrow 的使用。)
      • 当您不希望它抛出异常时,这是使用new 的最常见方式。但是不,更常见的是只使用new 并使用 异常处理。如果分配失败,您通常也无能为力,因此让异常传播是一种非常干净的优雅退出方式。
      【解决方案4】:

      如果您使用shared_ptrunique_ptr,您可以指定自定义删除器。例如,

      struct free_delete
      {
          void operator()(void* x) { free(x); }
      };
      

      这可以与shared_ptr 一起使用,如下所示:

      std::shared_ptr<int> sp((int*)malloc(sizeof(int)), free_delete());
      

      如果你使用unique_ptr,删除器是unique_ptr类型的一部分,所以需要将删除器指定为模板参数:

      std::unique_ptr<int, free_delete> up((int*)malloc(sizeof(int)));
      

      但是,在编写 C++ 时,最好正确使用异常,而不是避免它们,尤其是在分配失败方面。在大多数情况下,您无法成功地从尝试进行分配的函数中的分配失败中恢复,因此异常可以帮助您处理实际能够处理的错误。

      【讨论】:

      • 也可以直接传freeauto myPointer = std::unique_ptr&lt;int, void (*)(void*)&gt;(..., free)
      • @PatrickChilton 请注意,如果您这样做,您的unique_ptr 将是原来的两倍。
      【解决方案5】:

      /* handle error */ 中有什么代码?对于内存不足的错误,您实际上可以做些什么吗?我只是让应用程序通过调用堆栈(核心转储)终止,所以我至少知道一个可能导致问题的地方。

      使用malloc 为 C++ 类和对象分配内存不是一个好主意,因为它不能确保构造函数被调用,可能会给你留下未初始化的类,如果它们有虚拟方法,它们甚至可能崩溃。

      只需使用newdelete 即可,不必担心会捕获异常,毕竟内存不足是一种异常情况,不应在应用程序的正常运行中发生。

      【讨论】:

      • 在某些情况下您可以处理错误。例如,内存贪婪的数值计算(例如模拟)很容易在弱机器上耗尽内存,但在这种情况下,您可以立即停止并显示错误而不是崩溃。
      【解决方案6】:

      您可能想尝试“新展示位置”。见What uses are there for "placement new"?

      【讨论】:

        【解决方案7】:

        使用nothrow

        Nothrow 常量

        这个常数值被用作 运算符 new 和运算符的参数 new[] 表示这些函数 不应抛出异常 失败,但返回一个空指针 而是。

        char* p = new (nothrow) char [1048576];
        if (p==NULL) cout << "Failed!\n";
        else {
            cout << "Success!\n";
            delete[] p;
        }
        

        【讨论】:

          【解决方案8】:

          最好的解决方案是使用new (std::nothrow) Type。这将像new Type 一样起作用,但如果失败,将给出 null 而不是抛出。这比试图让malloc 表现得像new 容易得多。

          如果你真的必须使用malloc,那么记得正确构造和析构对象:

          void* memory = malloc(sizeof(Type));
          Type* object = new (memory) Type;
          object->~Type();
          free(object); // or free(memory)
          

          你可以通过给它一个自定义删除器来使用它和一些智能指针:

          void malloc_deleter(Type* object)
          {
              object->~Type();
              free(object);
          }
          
          if (void* memory = malloc(sizeof(Type)))
          {
              Type* object = new (memory) Type;
              std::shared_ptr<Type> ptr(object, malloc_deleter);
              DoStuff(ptr);
          }
          

          但是使用不抛出的 new 会简单得多:

          if (Type* object = new (std::nothrow) Type)
          {        
              std::shared_ptr<Type> ptr(object);
              DoStuff(ptr);
          }
          

          【讨论】:

          【解决方案9】:

          我有一个问题。

          如果“Type”是构造函数可以抛出的类型,会发生什么?在这种情况下,仍然需要在 try/catch 块中处理异常。

          那么放弃基于异常的方法是个好主意吗?

          我想说,可以使用抽象工厂/工厂方法设计模式,并将所有“新”放在相对较少的文件/命名空间/类集中,而不是分散在各处。这也可能有助于将 try/catch 块的使用限制在相对较少的代码中。

          【讨论】:

            【解决方案10】:

            对于oneliner: unique_ptr&lt;char, void (*)(void*)&gt; buffer( (char*)malloc(size), free );

            【讨论】:

              猜你喜欢
              • 2018-07-18
              • 1970-01-01
              • 2021-01-07
              • 2020-03-16
              • 1970-01-01
              • 2021-03-09
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多