默认(可选)参数作为引用 c++

Default (Optional) Arguments as references c++

是否有可能(不使用 boost)在 C++ 中具有如下函数:

void foo(int x, classX &obj = *(new classX()))

classX 在我的代码库中多次使用,并且有许多具有相似签名的此类函数(即使用此 class 对象作为默认参数)。是否可以在不重载调用的情况下实现这一点?

可以使用全局共享实例作为默认参数。

extern inline classX globalClassX;
void foo(int x, classX &obj = globalClassX);

应该完成了。

但是,我不确定 static initialization order fiasco 可能会干扰。

这可以使用 Meyers Singleton 方法解决:

classX& getGlobalClassX()
{
  static ClassX classX;
  return classX;
}

void foo(int x, classX &obj = getGlobalClassX);

用于演示的 MCVE:

#include <cassert>
#include <iostream>

struct Object {
  inline static unsigned idGen = 1;
  unsigned id;
  const std::string name;
  explicit Object(const std::string &name = std::string()): id(idGen++), name(name) { }
};

Object& getGlobalObj()
{
  static Object objGlobal("global");
  return objGlobal;
}

void doSomething(int x, Object &obj = getGlobalObj());

#define PRINT_AND_DO(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__ 

int main()
{
  PRINT_AND_DO(doSomething(0));
  PRINT_AND_DO(Object obj("local"));
  PRINT_AND_DO(doSomething(1, obj));
  PRINT_AND_DO(doSomething(2));
}

void doSomething(int x, Object &obj)
{
  std::cout << "doSomething(x: " << x << ", obj: Object("
    << obj.id << ", '" << obj.name << "'))\n";
}

输出:

doSomething(0);
doSomething(x: 0, obj: Object(1, 'global'))
Object obj("local");
doSomething(1, obj);
doSomething(x: 1, obj: Object(2, 'local'))
doSomething(2);
doSomething(x: 2, obj: Object(1, 'global'))

Live Demo on coliru


另一个Q/A我在写的时候参考了:

您提供的代码当然可以编译 "works",但我强烈反对这样的事情。

函数 returns void 这意味着引用或分配的对象(或其假定的所有者)不会离开函数。因此,如果分配了它,就必须将其销毁(否则,那是其他人的问题,在该功能之外)。

但是,这根本不可能,没有人拥有该对象,也没有指向它的指针!所以你不仅有 possible 内存泄漏,还有 guaranteed 内存泄漏(如果没有传递对象),除非你添加另一个丑陋的 hack,它从引用中派生出一个指针,只是为了销毁对象。太不爽了。

此外,即使您完成了此操作(以无泄漏的方式),每次函数调用都会进行无用的对象分配和销毁。尽管不应该过早优化,但 不应该通过添加不仅不必要而且实际上会降低代码质量的常规分配和释放来过早悲观。

更好的是:

//namespace whatever {
classX dummy;
//}
#include <memory>

void foo(int x, classX &obj = dummy)
{
    if(std::addressof(obj) != std::addressof(dummy))
    { /* do something using object */ }
    else
    { /* no object supplied */ }
}

是的,这是一个用于良好事业的全局。如果让您感觉更好,您可以将全局设置为单例,或者设置为静态 class 成员,都一样。无论哪种方式,您只有一个对象,没有分配,没有泄漏,如果您愿意,您仍然可以将对象传递给函数。而且,你可以区分这两种情况。