题
我假设运算符+的规范形式,假设存在重载运算符+ =成员函数,就像这样:
const T operator+(const T& lhs, const T& rhs)
{
return T(lhs) +=rhs;
}
但有人向我指出,这也有效:
const T operator+ (T lhs, const T& rhs)
{
return lhs+=rhs;
}
本质上,这个表单将临时的创建从实现的主体转移到函数调用。
为这两个参数设置不同类型似乎有点尴尬,但是第二种形式有什么问题吗?是否有理由偏爱另一个?
解决方案
根据编辑过的问题,首选表格将是首选。编译器更可能优化返回值(您可以通过在T的构造函数中放置断点来验证这一点)。第一种形式也将两个参数作为const,这是更理想的。
关于返回值优化主题的研究,例如此链接作为一个简单示例: http://www.cs.cmu.edu/~gilpin/c++/performance.html
其他提示
我不确定两者的生成代码是否存在太大差异。
在这两者之间,我(个人)更喜欢第一种形式,因为它更能传达意图。这是关于你对+ =运算符的重用以及通过const&传递模板化类型的惯用语。
我更喜欢第一种形式的可读性。
在我看到第一个参数被复制之前,我不得不三思而行。我没想到。因此,因为两个版本可能同样有效,我会选择一个更容易阅读的版本。
const T operator+(const T& lhs, const T& rhs)
{
return T(lhs)+=rhs;
}
如果你想要简洁,为什么不呢?
我的第一个想法是第二个版本可能比第一个版本快得多,因为没有引用作为参数被推入堆栈。但是,这将依赖于编译器,并且取决于编译器是否执行命名返回值优化。
无论如何,如果有任何疑问,永远不要选择可能甚至不存在的非常小的性能增益而且您可能不需要 - 选择最清晰的版本,这是第一个。
实际上,第二种是首选。如c ++标准中所述,
3.7.2 / 2:自动存储持续时间
如果命名的自动对象有 初始化或析构函数 副作用,它不应该 在街区结束前被摧毁, 也不应该作为一个被淘汰 优化,即使它似乎是 未使用的,除了类对象或 其副本可能会被删除 在12.8。中指定。
也就是说,因为使用复制构造函数创建了未命名的临时对象,所以编译器可能不会使用返回值优化。但是,对于第二种情况,允许使用未命名的返回值优化。请注意,如果您的编译器实现了命名返回值优化,那么最好的代码是
const T operator+(const T& lhs, const T& rhs)
{
T temp(lhs);
temp +=rhs;
return temp;
}
我认为,如果你将它们都内联(我会因为它们只是转发函数,并且可能是运算符+ =()函数是脱节的),你将得到几乎无法区分的代码生成。也就是说,第一个更规范。第二个版本是不必要的“可爱”。