2

更新:

  1. 因此,根据 Jean 的评论,我查看了此链接。这实际上非常接近我要问的问题。唯一的区别是它明确地处理类(这cv::UMat无疑是);

    但是,我尝试对返回类型进行的功能嵌套是否仍然有效?是否仍会出现复制省略,并达到预期的结果?


问题

我目前正在使用 OpenCV 的cv::UMat对象类,我的同事编写了一个函数来进行cv::UMat添加,如下所示:

UMat addUMats(UMat & M1, UMat & M2){
    UMat returnMat;
    add(M1, M2, returnMat);
    return move(returnMat);}

现在,如果我这样称呼它,这很好用:

cv::UMat A = data1; 
cv::UMat B = data2; 
cv::UMat C = addUMats(A, B); 

但是,当我尝试将函数作为参数传递给函数时,出现“参数必须是左值”类型错误。例如,

cv::UMat A = addUMats(addUMats(alpha, beta), addUMats(alpha, beta));

对于任何有效cv::UMats的 , alpha, beta

至今

我做了一些研究,发现它std::move(input)显式地返回了一个右值类型的临时值。因此,抛出错误是有道理的。

我意识到我可以通过首先执行以下操作来解决此问题:

cv::UMat inputA = addUMats(alpha, beta);
cv::UMat A = addUMats(inputA, inputA); 

或者,我什至可以做类似的事情,

UMat addUMats(UMat & M1, UMat & M2){
    UMat returnMat;
    add(M1, M2, returnMat);
    return returnMat;}

在这种情况下,我的理解是该行将return returnMat导致一个 deep(?) 临时被复制。

问题

所以,我知道这里可能会发生一些依赖于 OpenCV 的事情;就像,也许是因为 UMat 类型正在进行一些时髦的铸造等。

但是,在一般情况下,适应函数的最佳方法 addUmats能够将函数作为对函数的调用?

在运行时方面,我将寻求最有效的解决方案。另外,我不希望这个问题仅限于 OpenCV 案例;获得使用该std::move(input)调用的任何类型函数的答案将不胜感激。

4

3 回答 3

2

我认为您在函数的输入参数中遗漏了一些const。尝试如下:

UMat addUMats(const UMat & M1, const UMat & M2) {
    UMat returnMat;
    add(M1, M2, returnMat);
    return move(returnMat);
}

可能不是唯一的问题,但就目前而言,您的函数不能将临时变量作为输入,因为它假定它们可以在函数内部进行修改。

于 2017-03-08T20:11:26.113 回答
1

当您使用 then 返回局部变量时,std::move您不允许编译器执行 RVO(返回值优化),这是因为您返回对 UMat 的引用,该引用与 UMat 的类型不同,并且标准要求返回相同的类型,如果允许编译器执行 RVO。

如果编译器无论如何选择不使用 RVO,则返回的对象必须被视为右值,因此当允许 RVO 时,要么使用复制省略,要么隐式应用 std::move。

这里:

cv::UMat A = addUMats(addUMats(alpha, beta), addUMats(alpha, beta));

问题在于addUMats按值返回,并addUMats接受引用但对左值引用。解决方案是添加 addUMats 的右值版本:

UMat addUMats(UMat && M1, UMat && M2)
于 2017-03-08T20:04:09.780 回答
1

你的问题

您不能将右值传递给您的函数,因为该函数特别需要一个左值(an UMat&)。

可以这样想:addUMats的参数可以在函数内部更改。但是,当您这样做时addUMats(addUMats(alpha, beta), addUMats(alpha, beta));,您将调用addUMats两个您以后将无法访问的临时值。


可能的解决方案

从概念上讲,添加两个矩阵 A 和 B 不应更改 A 或 B。因此,如果您确定您的同事不会更改函数内部的 A 或 B,他们可以将函数的签名更改为:

UMat addUMats(const UMat & M1, const UMat & M2)

在这种情况下,问题解决了!您将能够调用addUMats两个临时对象。既然它们无论如何都不会改变,那也没关系。

如果您需要优化代码并利用右值优化,您还可以使用以下方法重载函数:

UMat addUMats(const UMat && M1, const UMat && M2)
于 2017-03-08T20:12:08.730 回答