I've just started learning multi-threading in C++ and following this excellent tutorial.
However when I print the memory address of the string being returned in Future I'm getting a different address.
Here's my code.
#include<iostream>
#include <thread>
#include <future>
#include <string>
void thFunc(std::promise<std::string> && prms) {
std::string str("Hello from future ^^");
std::cout << "Location=" << (void*)str.data() << "\n";
prms.set_value(str);
}
int main() {
std::promise<std::string> prms;
std::future<std::string> ftr = prms.get_future();
std::thread th(&thFunc, std::move(prms));
std::printf("Hello from main!!\n");
std::string futStr = ftr.get();
std::cout << futStr << "\t Location= " << (void*)futStr.data() << "\n";
th.join();
return 0;
}
How I'm compiling it:
clang++ -g -Wall -std=c++11 -stdlib=libc++ -o future_ex future_ex.cpp
And here's the output that I'm getting:
Hello from main!!
Location=0x30cdbff01
Hello from future ^^ Location= 0x30cd3dfa1
I checked the documentation of get() and it does uses std::move which means that there's no copy in between. So not sure why address is different.
Any help/explanation on this behaviour would be great :)
Please let me know if more info is needed.
EDIT:: Based on the comments here's a shot using shared_ptr. Modified the code to use shared_ptr (excluding imports)
void thFunc(std::promise<std::shared_ptr<std::string>> & prms) {
std::string str("Hello from future ^^");
std::shared_ptr<std::string> shared = std::make_shared<std::string>(str);
std::cout << "Address in thread=" << shared.get() << " String= " << *shared.get() << "\n";
prms.set_value(shared);
}
int main() {
std::promise<std::shared_ptr<std::string>> prms;
std::future<std::shared_ptr<std::string>> ftr = prms.get_future();
std::thread th(&thFunc, std::ref(prms));
std::printf("Hello from main!!\n");
std::shared_ptr<std::string> futSharedPtr = ftr.get();
std::cout << "Address in main= " << futSharedPtr.get() << " Value= " << *futSharedPtr.get() << "\n";
std::cout << "COUNT:: " << futSharedPtr.use_count() << "\n";
th.join();
return 0;
}
Here's the output:
Hello from main!!
Address in thread=0x60000298c018 String= Hello from future ^^
Address in main= 0x60000298c018 Value= Hello from future ^^
COUNT:: 1
prms.set_value(str);
this line is a copy of str
into the promise.
prms.set_value(std::move(str));
now you move the string in.
However, if the string is short, you can still experience the small string optimisation (SSO, or SBO for small buffer optimization). std::string
does not mandate that its data is stored on the heap; in fact, it encourages that its data be stored within the std::string
itself if short, saving a heap allocation.
"Hello from future ^^"
is short enough to fit in most SSO buffers for std::string
s.
Use a longer string, and properly move, and those addresses will match.
A good way to debug "where did that copy come from" is to use a move-only type.
Take your shared
implementation and use unique_ptr
. Now it fails to work at the point where the copy occurs!
void thFunc(std::promise<std::unique_ptr<std::string>> & prms) {
std::string str("Hello from future ^^");
auto ptr = std::make_unique<std::string>(str); // copy here, add std::move
std::cout << "Address in thread=" << shared.get() << " String= " << *ptr.get() << "\n";
prms.set_value(ptr); // ERROR: copy here, add std::move
}
int main() {
std::promise<std::unique_ptr<std::string>> prms;
auto ftr = prms.get_future();
std::thread th(&thFunc, std::ref(prms));
std::printf("Hello from main!!\n");
auto ptr = ftr.get();
std::cout << "Address in main= " << ptr.get() << " Value= " << *ptr.get() << "\n";
th.join();
return 0;
}