【问题标题】:Why do many init functions take a pointer to initialize, rather than returning a valid one? [duplicate]为什么许多初始化函数需要一个指针来初始化,而不是返回一个有效的? [复制]
【发布时间】:2012-08-12 01:51:56
【问题描述】:

可能重复:
pointer as second argument instead of returning pointer?

我经常看到这个:

Monkey* test = malloc(sizeof(Monkey));
Monkey_New(test);

让init函数返回指针不是更简洁吗?

Monkey* test = Monkey_New();

为什么经常使用第一种方式?

【问题讨论】:

  • 如果您的第一个替代代码在test 的定义和对Monkey_New 的调用之间包含诸如test = malloc(sizeof *test); 之类的内存分配,那么您应该显示它。否则,此代码是无意义的,因为它将未初始化的对象传递给 Monkey_New。
  • 你的第一个例子是错误的。它应该是 Monkey_New(&test)。否则不可能在“Monkey_New”函数中分配指针,该函数只接收作为参数给出的指针的副本。
  • 是的,从来没有解决过这个问题......哎呀

标签: c pointers init


【解决方案1】:

这完全取决于开发人员使用的命名约定。考虑到这一点:

http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Default_Constructors

对于 c++ 和 c,告诉你使用 new 并接受参数来帮助初始化,返回初始化的值。以前不是这样的,因为那时候是个蛮荒的世界。为了体面,使用 Monkey_New();

【讨论】:

    【解决方案2】:

    这两种设计在功能上截然不同。你要问的那个把分配的负担放在调用者身上。这有一个巨大的优势,如果对象不必超过调用者,则可以避免动态存储(malloc);它可以存储在自动变量中。这也意味着,假设 init 函数不必获取更多资源,您可以拥有一个无故障 API,调用者不必检查故障。另一方面,它要求将结构的定义(至少大小)暴露给调用模块,这意味着如果更新库代码以使用更大大小的对象,则必须重新编译调用者;因此,对于旨在拥有长期稳定 ABI 的共享库来说,这可能是负面的。

    在您指出的替代设计中,获取存储的负担由被调用者(库函数)承担,并且它必须使用动态存储(malloc),因为自动存储无法在返回给调用者后继续存在。这样更抽象更干净,

    【讨论】:

    • 谢谢;我没有考虑到这一点。我想,由于最近使用了许多仅堆结构,我的想法变得模糊了。
    • 大小不需要在构建时暴露。大小可以由运行时例程提供。那么在不同版本的软件中改变大小就不需要重新编译库的用户了。
    • @Eric:那么调用者仍然必须使用动态存储,除非你想陷入丑陋的 VLA hacks(丑陋,因为以任何可移植的方式确保对齐都不是一件容易的事)。
    • @R.. 很好的答案,但我不会将替代设计归类为“更清洁”,因为谁释放了对象?如果调用者曾经给出它获得的指针,那么你就会陷入混乱。第一个选项将内存管理与“对象”功能分开,这是更干净的恕我直言。此外,对于从不使用 malloc 的系统,第一个选项是唯一简单的方法。
    • 另外,如果它是这样写的 size_t Monkey_New(void*, size_t max_size),那么你可以在一定程度上应对库类型的变化。必须将 Monkey 隐藏在界面后面,同时提供 size_t Monkey_sizeof(void)。
    猜你喜欢
    • 1970-01-01
    • 2021-11-29
    • 2015-05-01
    • 1970-01-01
    • 2012-08-23
    • 2019-04-18
    • 2018-01-09
    • 2014-12-26
    • 1970-01-01
    相关资源
    最近更新 更多