是否构造了伪参数的对象参数?

Alw*_*ing 12 c++

假设一个功能模板:

template <class T>
void foo(T /* dummy */) {...}
Run Code Online (Sandbox Code Playgroud)

假设这样foo调用:

foo(Widget());
Run Code Online (Sandbox Code Playgroud)

Widget在这种情况下是否会构建一个对象?

这篇文章提出了一个关于未使用的参数的类似问题(虚拟参数的参数肯定未被使用).回复表明,除非通过函数指针调用函数,否则编译器将优化未使用的参数.

但是,请考虑Alexandrescu 在Modern C++的2.5节中的以下文本:

现在说你的应用程序中有一条规则:Widget类型的对象是不可触及的遗留代码,在构造时必须带两个参数,第二个是固定值,如-1.从Widget派生的您自己的类没有这个问题.

...

在没有部分专业化功能的情况下,唯一可用的工具又是重载.解决方案是传递类型为T的虚拟对象并依赖于重载:

template <class T, class U>
T* Create(const U& arg, T /* dummy */)
{
   return new T(arg);
}
template <class U>
Widget* Create(const U& arg, Widget /* dummy */)
{
   return new Widget(arg, -1);
}
Run Code Online (Sandbox Code Playgroud)

这样的解决方案将导致构造仍未使用的任意复杂对象的开销.

这表明编译器不够智能,无法避免伪参数的构造...

那么,哪个是正确的?如果Alexandrescu是正确的,那为什么不进行这种优化呢?

Yak*_*ont 15

创建对象可能会产生副作用.

除非编译器能够证明没有副作用发生,或者没有标准要求副作用发生,否则在as-if下不允许消除这种对象的创建(编译器可以对你做任何事情)代码,只要它表现得如果 - 如果它们没有进行更改,达到标准的要求)或elision(在某些情况下合并某些对象的生命周期,即使它不表现为 - 如果你没有合并他们的规则.

例如,假设Widgets在中心位置注册了它们的存在.当对象被创建时,存在的小部件的数量将增加1 - 使得未发生的小部件在标准下是非法的.

即使没有副作用,证明没有副作用需要编译器收集创建Widget所涉及的所有代码,并分析它"最终无所作为".这可能会有所不同(大量代码的链接时优化,特殊的"对象将在时间Y消失",以确定是否有任何副作用),不可能(我们正在谈论分析非图灵完整计算结果的平凡属性).

所有这一切都是针对一个相对奇怪的角落案例,其中"有人无缘无故地创造了一个物体,然后在不使用它的情况下将其丢弃".


Lig*_*ica 11

这不是"聪明"; 这是关于正确的.标准中没有规则可以省略这种结构.如果构造函数没有副作用,那么只能通过as-if规则来避免.

更一般地,呼叫站点处的代码并不总是能够知道该参数在定义站点处是否为"虚拟".否则,语言可能有不同的指定,尽管这纯粹是猜测.


让我们std::string以一个例子为例,仅仅为了论证(lol):

翻译单位1

// (N.B. no variable name; therefore "dummy")
void foo(std::string)
{}
Run Code Online (Sandbox Code Playgroud)

翻译单位2

#include <string>

void foo(std::string argument);

int main()
{
   foo("will this be used to construct a std::string?");
}
Run Code Online (Sandbox Code Playgroud)

是的,因为就TU2而言,它必须是.


在相反的例子中,忽略构造显然是一个可怕的错误:

翻译单位1

#include <string>
#include <iostream>

void foo(std::string argument)
{
    std::cout << argument << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

翻译单位2

#include <string>

// (N.B. no variable name; therefore "dummy")
void foo(std::string);

int main()
{
   foo("will this be used to construct a std::string?");
}
Run Code Online (Sandbox Code Playgroud)

不(通过你的"建议"),导致正确的混乱.


根据C++编译模型的性质,这两种情况都是100%无法检测到的.