gpt4 book ai didi

引用的 C++ 复制省略

转载 作者:可可西里 更新时间:2023-11-01 18:37:41 27 4
gpt4 key购买 nike

考虑到以下简化代码是否保证 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 的影响。

什么时候会发生复制省略,这会导致不同的线程返回同一个对象而不是它们自己的拷贝吗?如果是这样,如何避免这种情况?

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

最佳答案

你的代码没问题。当编译器意识到它可以优化掉临时对象并改为在适当的位置构造新对象时,就会发生复制省略。 map::operator[] 返回对其值类型的引用这一事实是无关紧要的,该函数不返回引用。因此,

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

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

都将返回拷贝。不同之处在于,在第一种情况下,您的编译器很可能会使用复制省略/RVO(即不调用复制构造函数),而在第二种情况下,它必须调用复制构造函数并进行复制。

如果你的编译器没有使用复制省略/RVO,那么根据 C++11 标准返回的值是一个临时值(在第一种情况下),并且由于类 std::string 是可移动的,临时值将是感动。例如,

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

因此,事先说明是否使用移动语义或是否会发生复制省略/RVO 并不总是很明显,这取决于您的编译器。如果你愿意,你可以强制移动语义,通过使用

std::move

编辑:顺便说一句,您甚至不能返回对临时对象的引用。您不能引用 r 值(临时)。

关于引用的 C++ 复制省略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31378748/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com