如何在预期移动情况下检测意外副本

时间:2019-07-19 05:03:29

标签: lambda copy c++14 move mutable

当我使用lambda表达式时,有时会移动捕获可复制和可移动的对象。在下面的示例中,对象为t,类型为tracer。在lambda表达式中,我想再次将t移至其他函数f()f()的参数是按值传递的,因为我想同时支持f()的复制和移动。

我称main()的第一部分为f(std::move(t)),但由于t被捕获为const变量,所以它没有被移动而是被复制了。我将main()函数的第二部分添加到了mutable的lambda表达式中。它按预期运行。

我经常忘记在lambda表达式中添加mutable。如果t是仅移动类型,则第一种情况将导致编译错误。我很容易注意到这个问题。但是,如果t是可复制且可移动的,那么我很难注意到意外的复制。我想检查一下这种情况。

有什么好办法吗?

#include <iostream>

struct tracer {
    tracer() {
        std::cout << __PRETTY_FUNCTION__ << ":" << this << std::endl;
    }
    ~tracer() {
        std::cout << __PRETTY_FUNCTION__ << ":" << this << std::endl;
    }
    tracer(tracer const& other) {
        std::cout << __PRETTY_FUNCTION__ << ":" << this << " <- " << &other << std::endl;
    }
    tracer(tracer&& other) {
        std::cout << __PRETTY_FUNCTION__ << ":" << this << " <- " << &other << std::endl;
    }
    tracer& operator=(tracer const& other) {
        std::cout << __PRETTY_FUNCTION__ << ":" << this << " <- " << &other << std::endl;
        return *this;
    }
    tracer& operator=(tracer&& other) {
        std::cout << __PRETTY_FUNCTION__ << ":" << this << " <- " << &other << std::endl;
        return *this;
    }
};

void f(tracer) {
}

int main() {
    {
        tracer t;
        // move assign capture
        [t = std::move(t)] { // forget write mutable
            f(std::move(t)); // I expect move but copy due to lack of mutable
        }();
    }
    std::cout << "---" << std::endl;
    {
        tracer t;
        // move assign capture
        [t = std::move(t)] () mutable {
            f(std::move(t)); // Moved as I expected
        }();
    }
}

正在运行的演示:https://wandbox.org/permlink/vphaVOXYhN0sr42o

1 个答案:

答案 0 :(得分:0)

我认为我想出了一个解决方案。我为std::move()编写了以下包装。

template <typename T>
typename std::remove_reference_t<T>&&
only_move(T&& t) {
    static_assert(!std::is_const_v<std::remove_reference_t<T>>, "T is const. Fallback to copy.");
    return std::move(t);
}

我将std::move()替换为only_move()如下:

int main() {
    {
        tracer t;
        // move assign capture
        [t = only_move(t)] { // got static assertion failed *1
            f(only_move(t)); // I expect move but copy due to lack of mutable
        }();
    }
    std::cout << "---" << std::endl;
    {
        tracer t;
        // move assign capture
        [t = only_move(t)] () mutable {
            f(only_move(t)); // Moved as I expected
        }();
    }
}

然后,仅当我忘记mutable时,我才会收到静态声明失败的消息。

* 1错误:由于要求'!std :: is_const_v',static_assert失败。“ T为常量。要复制的后备。

正在运行的演示:https://wandbox.org/permlink/3HlrAab0IAUYQON8