如果构造函数在 C++ 中分配内存失败怎么办?

发布于 2024-09-07 19:51:21 字数 395 浏览 8 评论 0原文

我刚刚遇到一个问题,类的构造函数需要分配内存。所以我很高兴地写了char *mem = static_cast(malloc(100*sizeof(*mem)));。但后来我突然意识到,如果出现错误,我无法返回错误代码(我没有在代码中使用异常)。我该如何解决这个问题?

我是否应该添加一个 boolinitialed 成员,然后在创建我的类后立即检查它,如:

myClass mc;
if (!mc.initialized) {
    printf("Memory allocation failed in mc's constructor\n");
    exit(1);
}

谢谢,Boda Cydo。

I just came across a problem where the constructor of a class needs to allocate memory. So I happily wrote char *mem = static_cast<char*>(malloc(100*sizeof(*mem)));. But then I suddenly realized that in case of error I can't return error code (I am not using exceptions in my code). How can I solve this problem?

Should I add an bool initialized member and then after making my class and then check it right after, as in:

myClass mc;
if (!mc.initialized) {
    printf("Memory allocation failed in mc's constructor\n");
    exit(1);
}

Thanks, Boda Cydo.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

满天都是小星星 2024-09-14 19:51:21

您应该使用 new,而不是 malloc。当内存不足时 new 会抛出 std::bad_alloc 。如果分配失败(或由于任何其他原因导致初始化出现问题),则应从构造函数传播异常,因为这是防止调用析构函数的唯一方法。如果构造函数成功完成,则必须调用析构函数(当然,除非它是在堆上分配且从未释放)。

You should use new, not malloc. new throws std::bad_alloc when you are out of memory. An exception should be propagated from the constructor if you fail to allocate (or for any other reason have a problem with initialization), as this is the only way you prevent the destructor from being called. If the constructor successfully completes, the destructor must be called (unless, of course, it was heap allocated and never freed).

拥醉 2024-09-14 19:51:21

这就是例外被发明的目的。另外,请使用 new 而不是 malloc(3)

That's what exceptions were invented for. Also, use new instead of malloc(3).

寄人书 2024-09-14 19:51:21

如果您不使用异常,则不应使用构造函数(或者不应编写可能失败的构造函数),因为正如您所注意到的,除了通过异常之外,无法从构造函数报告错误。您可以交替使用工厂函数,并使用它来将可能失败的位与不能失败的位解耦。

class myClass {
  private:
  char *m_malloced_buffer;

  // disallow calling ctors/dtors directly
  myClass(char *malloced_buffer) : m_malloced_buffer(malloced_buffer) {}
  ~myClass() { free(m_malloced_buffer); }

  public:
  static myClass *create()
  {
     char *buf = static_cast<char*>(malloc(100*sizeof(*mem)));
     if(!buf) return NULL;

     void *myClassRes = malloc(sizeof(myClass));
     if(!myClassRes) return NULL;
     new (myClassRes) myClass(buf); // placement new, uses existing memory to invoke the ctor
     return static_cast<myClass*>(myClassRes);
  }
  static void destroy(myClass* val)
  {
     if(!val) return;
     val->~myClass(); // explicitly invoke dtor
     free(val); // deallocate memory
  }
};
...
myClass *val = myClass::create();
if(val) { ... }
myClass::destroy(val);

在本示例中,我使用 malloc 和 free 来完成所有分配,您可以使用 new (std::nothrot)并同样轻松删除。您必须将可能失败的每个操作从构造函数中提取出来并提取到工厂函数中,以便您可以在不使用异常的情况下检查错误。即使在这个简单的例子中,你也可以看出这是一个巨大的痛苦。您说您在评论中了解到“异常不是良好的编码风格”,您的意思是您了解到这一点(无论是通过合理论证和解释的指导,还是根据经验),或者有人说“异常”不是好的编码风格”并且您已接受该声明作为教条?

使用 bool 初始化成员会导致僵尸对象问题(请参阅 http://www .parashift.com/c++-faq-lite/exceptions.html)。

If you're not using exceptions, you shouldn't use constructors (or shouldn't write constructors that can fail), because as you've noticed, there is no way to report an error from a constructor except via an exception. You can alternately use a factory function and use that to decouple the bits that can fail from the bits that can't

class myClass {
  private:
  char *m_malloced_buffer;

  // disallow calling ctors/dtors directly
  myClass(char *malloced_buffer) : m_malloced_buffer(malloced_buffer) {}
  ~myClass() { free(m_malloced_buffer); }

  public:
  static myClass *create()
  {
     char *buf = static_cast<char*>(malloc(100*sizeof(*mem)));
     if(!buf) return NULL;

     void *myClassRes = malloc(sizeof(myClass));
     if(!myClassRes) return NULL;
     new (myClassRes) myClass(buf); // placement new, uses existing memory to invoke the ctor
     return static_cast<myClass*>(myClassRes);
  }
  static void destroy(myClass* val)
  {
     if(!val) return;
     val->~myClass(); // explicitly invoke dtor
     free(val); // deallocate memory
  }
};
...
myClass *val = myClass::create();
if(val) { ... }
myClass::destroy(val);

In this example I've used malloc and free to do all the allocating, you could use new (std::nothrow) and delete just as easily. You'll have to extract every operation that can fail out of your ctor and into the factory function so that you can check for errors without using exceptions. Even in this simple example, you can see this is a huge pain in the neck. You say you learned that "exceptions are not good coding style" in a comment, do you mean you learned that (whether by instruction with reasoned arguments and explanations, or from experience), or someone said "exceptions are not good coding style" and you've accepted the statement as dogma?

Using a bool initialized member leads to the zombie object problem (see http://www.parashift.com/c++-faq-lite/exceptions.html).

断桥再见 2024-09-14 19:51:21

如果您使用的是 C++ 而不是 C,您可能应该使用 new 而不是 malloc。抛出异常可能是您想要在构造函数中执行的操作。

如果您因为不想要异常而使用 new (nothrow),或者您正在使用 malloc,那么您可以简单地测试返回的指针是否为 NULL。然后,您可以设置一个成员变量来指示该对象处于失败状态。这可以在标准 C++ 库的流类中看到。

If you're using C++ and not C you should probaly be using new instead of malloc. Throwing an exception is probably what you want to do from within your constructor.

If you're using new (nothrow) though because you don't want an exception,or you are using malloc then you can simply test the pointer that is returned for NULL. You would then set a member variable which indicates that the object is in a failed state. This is seen in streams classes of the standard C++ library.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文