效率

时间:2017-03-08 19:49:27

标签: c++ function opencv reference copy-elision

更新

  1. 所以,根据Jean的评论,我看了this link。这实际上非常接近我提出的问题。唯一的区别是它明确地处理了类(cv::UMat毫无疑问是);
      

    但是,我尝试使用返回类型的函数嵌套是否仍然有效?是否仍然会出现复制省略,并达到预期的结果?

  2. 问题

    我目前正在使用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::UMatsalpha, beta

    到目前为止

    我做了一点research并发现std::move(input)显式返回一个rvalue类型的临时值。因此,抛出错误是有道理的。

    我意识到我可以先解决这个问题:

    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;}
    

    在这种情况下,我理解行[{1}}将导致复制深(?)临时。

    问题

    所以,我知道可能会有一些OpenCV依赖的东西在这里发生;也许是因为UMat类型有一些时髦的铸造正在进行或类似。

      

    但是,在一般情况下,调整 {/ em> return returnMat等函数的最佳方法是什么才能将函数作为对函数的调用?

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

3 个答案:

答案 0 :(得分:2)

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

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

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

答案 1 :(得分:1)

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

如果编译器选择不使用RVO,则返回的对象必须被视为rvalue,因此当允许使用RVO时,将使用复制elision或隐式应用std :: move。

下面:

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

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

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

答案 2 :(得分:1)

您的问题

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

以这种方式思考:addUMats的参数可以在函数内部进行更改。但是当您执行addUMats(addUMats(alpha, beta), addUMats(alpha, beta));时,您正在使用以后无法访问的两个临时值调用addUMats

可能的解决方案

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

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

在那种情况下,问题解决了!您可以在两个临时对象上调用addUMats。因为它们无论如何都不会改变,所以并不重要。

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

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