C++ copy elision for references
Considering the following simplified code is the caller of Cache::operator[] guaranteed to receive a copy of the mapped value?
#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;
}
As seen my intention is concurrency and after release of the mutex the continued existence of the mapped value is not guaranteed.
std::map<>::operator[]
returns a reference std::string&
. My understanding is that copy construction produces a nameless temporary which may then be subject to RVO.
When will copy elision occur and could this result in different threads being returned the same object rather than their own copies? If so how can this be avoided?
The actual code is involves a database lookup filling the cache with the map key being the table primary key and the mapped value an object constructed from the row fields.
The code you have is fine. Copy elision occurs when the compiler realizes that it can optimize away temporary objects and instead construct the new object in place instead. The fact that map::operator[] returns a reference to its value type is irrelevant, the function is not returning a reference. Therefore,
// case 1
std::string myFunction()
{
return std::string("Hello");
}
// case 2
std::string myFunction(int k)
{
return m_map[k];
}
will both return copies. The difference is that in the first case your compiler will most likely use copy elision/RVO (ie copy constructor is not called), whereas in the second case it must call the copy constructor and make a copy.
If your compiler did NOT utilize copy elision/RVO, than by the C++11 standard the returned value is a temporary (in the first case), and since the class std::string is movable, the temporary would be moved. For example,
std::string newStr = myFunction(); // RHS returns an r-value => move-semantics is used
It is therefore not always obvious beforehand to say if move-semantics will be used or if copy elision/RVO will occur, it depends on your compiler. You can force move-semantics if you want though, by using
std::move
Edit: Btw, you wouldn't even be allowed to return a reference to a temporary. You can't take the reference of an r-value (temporary).
Copy elision is simply a compiler optimization that is implemented in order to avoid needless copies when dealing with temporary objects. In your case, you are not returning a temporary, but the value from a member variable. Since you are returning it by value, it will be copied. There's no way around it.
链接地址: http://www.djcxy.com/p/86562.html上一篇: 简单的字符串压缩:删除连续的重复子字符串
下一篇: C ++复制elision参考