【发布时间】:2020-11-27 16:44:51
【问题描述】:
我正在研究 EDDSA 数字签名的实现,并且由于计算中使用的值的大小可以高达 521 位(缩放器)并且点具有三个缩放器(投影坐标),因此通过副本传递值在条款上是昂贵的堆栈空间和参数副本。为了消除尽可能多的副本,我将参数作为“const &”传递,创建一个局部变量,执行计算并将结果放入局部变量中,然后返回局部变量。注意:代码是 C++17 (clang)。
struct Point { /* ... */ } ;
friend Point operator + (Point const & lhs , Point const & rhs)
{
Point res ;
/* Do addition and place result into 'res' */
return res ;
}
这适用于所有可能的参数类型(&、const &、&&),但总是需要额外的堆栈空间来存储结果。如果传递了一个临时值(Point &&),它可以用来保存结果并节省堆栈空间。这里的问题是如何正确返回结果?
friend Point operator + (Point && lhs , Point const & rhs)
{
/* Do addition and place result into 'lhs' */
return lhs ; // Not sure what is exactly returned here : Danger of dangling reference or ok?
}
/* OR */
friend Point && operator + (Point && lhs , Point const & rhs)
{
/* Do addition and place result into 'lhs' */
return std::move (lhs) ; // Danger of dangling reference to caller if not used correctly
}
我了解第二种情况(返回点 &&)如果调用者未正确处理,可能会导致引用悬空。
我已阅读有关返回 && 值的类似问题和答案,但我没有找到任何特定于将 && 参数作为值返回的内容(上面的第一种情况)。
C++ 究竟如何定义第一种情况的返回值行为(当参数为 Point && 时返回 Point)?
是否有更好(即:高效且安全)的方法来消除副本和重用临时参数内存?
此外,如果重载的运算符被声明为模板,我理解 '&&' 参数的处理方式不同以支持完美转发。
template <class Point> friend Point operator + (Point && lhs , Point const & rhs)
{
/* Do addition and place result into 'lhs' */
return lhs ;
}
'&& 参数与非模板定义中的处理方式有何不同(如果有的话),返回结果的正确方法是什么?
【问题讨论】:
-
与
friend相关吗?我宁愿删除它,因为你只能在类定义中使用它,但你把它放在外面 -
在第一种情况下,它总是返回一个新的
Point。没有悬空引用,因为它不是引用——它为返回值构造了一个新对象。 -
是的,朋友在我的库中是相关的,我直接在我的类中声明重载运算符,因为它们需要访问私有变量。此外,通过将它们直接放在里面,它消除了大量的“模板”限定前缀。
标签: c++ overloading rvalue