C ++复制elision参考

考虑到以下简化的代码,Cache :: operator []的调用者保证会收到映射值的副本

#include <string>
#include <map>
#include <mutex>
#include <iostream>

class Cache {
    public:
        std::string operator[] (int k) {
            std::lock_guard<std::mutex> lock(m_mutex);

            if (! m_map.count(k)) m_map[k] = "Hello world";
            return m_map[k];
        }

    private:
        std::mutex m_mutex;
        std::map<int, std::string> m_map;
};

int main (int argc, char *argv[]) {
    Cache c;
    auto v = c[42];
    std::cout << v << std::endl;
    return 0;
}

正如我看到的,我的意图是并发性,并且在释放互斥量之后,映射值的继续存在并不能保证。

std::map<>::operator[]返回一个引用std::string& 。 我的理解是,复制结构会产生一个无名的临时文件,然后可能会受RVO影响。

何时会发生复制冲突,并可能导致不同的线程返回相同的对象而不是自己的副本? 如果是的话,如何避免这种情况?

实际的代码涉及填充缓存的数据库查找,映射键是表主键,映射值是从行字段构建的对象。


你有的代码很好。 当编译器意识到它可以优化掉临时对象,而改为构建新对象时,复制elision就会发生。 map :: operator []返回对其值类型的引用是不相关的,该函数不返回引用。 因此,

// case 1
std::string myFunction()
{
    return std::string("Hello");
}

// case 2
std::string myFunction(int k)
{
    return m_map[k];
}

都将返回副本。 不同的是,在第一种情况下,您的编译器很可能会使用copy elision / RVO(即不调用复制构造函数),而在第二种情况下,它必须调用复制构造函数并复制副本。

如果您的编译器不使用copy elision / RVO,而不是使用C ++ 11标准,则返回的值是临时的(在第一种情况下),并且由于类std :: string是可移动的,所以临时文件将被移动。 例如,

std::string newStr = myFunction(); // RHS returns an r-value => move-semantics is used

因此,预先说明是否使用移动语义或复制elision / RVO会发生,这取决于您的编译器。 如果你愿意的话,你可以强制使用移动语义

std::move

编辑:顺便说一句,你甚至不会被允许返回一个临时的参考。 你不能采用r值的参考(临时)。


复制elision只是一个编译器优化,为了在处理临时对象时避免不必要的副本而实现。 在你的情况下,你不是返回一个临时值,而是来自一个成员变量的值。 既然你是通过价值来回报它,它会被复制。 没有办法绕过它。

链接地址: http://www.djcxy.com/p/86561.html

上一篇: C++ copy elision for references

下一篇: decompiling DEX into Java sourcecode