C ++ 11 std :: promise从线程返回std :: string,数据指针看起来没有被移动复制

时间:2014-01-20 02:23:18

标签: c++ multithreading c++11 thread-safety promise

我开始使用C ++ 11标准和内置线程。从我收集到未来的价值时,我们使用移动运算符来完成所有权,使其远离原始对象(就像旧的auto_ptr用于分配时)。我通过在线程期间在std :: string对象内打印出char数组的指针并在主要接收回指针后打印指针来测试它。但是,指针是不同的。如果有人能告诉我为什么他们在这个简单的代码中有所不同以及代码看起来像他们是平等的,我将不胜感激:

#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <chrono>
#include <string>
#include <thread>
#include <future>
using namespace std;
void thrfut(promise<string>&& promReceived)
{
    string strObj("Hello from future");
    cout << "Address of char array inside string inside of thread " << (void*)strObj.data() << endl;
    promReceived.set_value(strObj);
}
int main(int argc, char** argv) 
{
    promise<string> promiseOfText;
    future<string> futureText = promiseOfText.get_future(); // has to be before creating thread if the promise is passed rvalue reference, should be moved on calling get or not ? 
    thread threadHandlingPromise(&thrfut, std::move(promiseOfText));
    string stringReceived = futureText.get();
    cout << "Received from promise through thread: " << stringReceived  << endl;
    cout << "Address of of char array inside string received from promise in main " << (void*)stringReceived.data() << endl;
    threadHandlingPromise.join(); 
    return 0;
}

这是一个示例输出

Address of char array inside string inside of thread 0x10ebc9be1
Received from promise through thread: Hello from future
Address of of char array inside string received from promise in main 0x7fff510f68c9

fyi:OS X 10.9.1在Netbeans 8.0中使用Xcode 5 clang ++其他人在Ubuntu和Windows上运行代码并返回相同的地址。

编辑(参见答案中的评论)* * * * *

我试过了:

struct MYC 
{   MYC() = default;
    ~MYC() { delete _pInt; };
    MYC(const MYC & myc) { puts("MYC copy"); _pInt = nullptr; if(myc._pInt != nullptr) {   _pInt = new int{*myc._pInt}; } }  
    MYC(MYC && myc) { puts("MYC move"); delete _pInt; _pInt = myc._pInt; myc._pInt = nullptr; }
    void setMe(int value) { delete _pInt; _pInt = new int{value} ; }
    int * _pInt = nullptr;
};
void thrfut(promise<MYC>&& promReceived)
{
    MYC obj;
    obj.setMe(5);
    cout << "Address of int inside MYC inside thread " << (void*)obj._pInt << endl;
    promReceived.set_value(std::move(obj));    
}
int main(int argc, char** argv) 
{
    promise<MYC> promiseOfMYC;
    future<MYC> futureMYC = promiseOfMYC.get_future();  
    thread threadHandlingPromise(&thrfut, std::move(promiseOfMYC));
    auto mycReceived = futureMYC.get();
    cout << "Address of int inside MYC received from promise in main " << (void*)mycReceived._pInt << endl;
    cout << "Value of int inside MYC received from promise in main " << *(mycReceived._pInt) << endl;
    threadHandlingPromise.join(); 
    return 0;
}

得到了:

Address of int inside MYC inside thread 0x7fd1b9c00110
MYC move
MYC move
Address of int inside MYC received from promise in main 0x7fd1b9c00110
Value of int inside MYC received from promise in main 5

这确认了非字符串类的移动动态。

2 个答案:

答案 0 :(得分:3)

修改

我终于记得GNU libstdc ++ std::string使用引用计数。也许这解释了什么? (不是一切)

原始答案

(1)确实是系统依赖的

$ g++48 promiseStr.cpp -o promiseStr -Wall -Wextra -std=c++0x -O0 -g3 -pthread && echo OK
OK
$ ./promiseStr
Address of char array inside string inside of thread 0x7f4b400008d8
Received from promise through thread: Hello from future
Address of of char array inside string received from promise in main 0x7f4b400008d8

$ lsb_release -a
LSB Version: (snip)
Distributor ID: Ubuntu
Description:    Ubuntu 12.04.2 LTS
Release:        12.04
Codename:       precise
$ g++48 --version
g++48 (GCC) 4.8.1
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

(2)future<T>::get()返回T而不是&&T,因此stringReceived可能会被复制。

(3)您不妨在Linux上尝试ltrace,看看幕后发生了什么(对不起,我没有OS X机器。)

$ ltrace -n2 -f -C ./promiseStr 2>&1 | grep basic_string
[pid 6899]       std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&)(0x7f486c17fde0, 0x406ea0, 0x7f486c17fdef, 0x7f486c180700, 0x7f486c180700) = 0x7f48640008d8
[pid 6899]             std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&)(0x244e0b0, 0x7f486c17fde0, 0x7f4864000900, 0x7f486c17fd90, 0x7f486c17fd20) = 0x7f48640008d8
[pid 6899]         std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()(0x7f486c17fde0, 0xffffffff, 0, 0x7f4864000028, 0x244e038 <unfinished ...>
[pid 6899]         <... std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() resumed> ) = 1
[pid 6898]   std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string&&)(0x7fff5c17ece0, 0x244e0b0, 0x244e0b0, -1, 0x244e038) = 0x7f486cf723d8
[pid 6898]   std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()(0x244e0b0, 1, 0x244e0a0, -1, 0x244e060) = 0x244e0b0
[pid 6898]   std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)(0x60bd40, 0x7fff5c17ece0, 0x7fff5c17ece0, 0x203a6461, 0x7f486c53cab0) = 0x60bd40
[pid 6898]       std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()(0x7fff5c17ece0, 0x7f486c759250, 0x7f486c180700, 0x7f486c759250, 0) = 0

答案 1 :(得分:2)

promReceived.set_value(strObj);上,调用string的复制构造函数;不要移动构造函数。

虽然您使用promReceived.set_value(std::move(strObj));,但可能无法保证data()的返回值相同。正如Mehrdad所说,每个实现可能会有所不同,例如小字符串优化。< / p>

(编辑:你的实现可以使用库里面的复制构造函数。)