Reputation: 12371
I'm using C++11 to do some thread program.
Now I get such a situation:
I have a std::set<std::future<std::string>> results
to store some results of threads, of course all of these threads will return a string.
However, when I try to get the strings, I get an error as below:
passing xxx as 'this' argument of xxx discards qualifiers
According to this link, I think it's because I'm trying to call a non-const function which belongs to the element of the set
. In other words, the element of the set
is std::future<std::string>
and std::future<std::string>::get()
is non-const. This is why I get such an error.
If I'm right, does it mean that I can never declare a std::set<std::future>
because its get
is always unusable?
Here is my code:
set<future<string>> results;
results.insert(...); // insert some future
for(auto it = results.begin(); it != results.end();)
{
if (it->wait_for(std::chrono::seconds(0)) == std::future_status::ready)
{
string tmp = it->get(); // ERROR!!!
}
}
Upvotes: 0
Views: 252
Reputation: 275405
When thinking of what container to use, you should think "can I do this with a std::vector
?". If your answer is no, you should ask "no, really, can I do this with a std::vector
?".
using namespace std::literals;
std::vector<std::future<std::string>> results;
constexpr auto threads = 10;
for (int i = 0; i < threads; ++i) {
results.push_back( std::async( std::launch::async,
[i]{
std::this_thread::sleep_for( std::chrono::milliseconds((threads-i)%(threads/3)) );
std::stringstream ss;
ss << "hello world " << i;
return ss.str();
}
) );
}
for (auto it = results.begin(); it != results.end();) {
if (it->wait_for( 0s ) == std::future_status::ready) {
std::string tmp = it->get();
std::cout << tmp << "\n";
std::swap( *it, results.back() ); // noop if already at back
if (std::next(it)==results.end()) it = results.begin(); // do this before pop back
results.pop_back(); // Or this could invalidate it
if (results.begin()==results.end()) break; // empty vector has to be caught early, as it is invalidated if vector is now empty
continue;
} else {
++it;
if (it == results.end()) it = results.begin();
continue;
}
}
Doing this with a std::set
is both a bad and impossible idea.
A bad idea, because std::set
is a node based container that does effort to maintain sort order. We don't need nodes. We don't need a sort order. So we are using a more powerful container than we need.
Impossible, because the contents of std::set
are by design immutable.
Impossible, because std::future
provides no operator<
, nor is there a reasonable place to hook a user-provided comparison function onto them.
Note that shared_future
s have a const
get()
method, so they can be stored in an immutable manner. But they still provide no "hooks" for a user-provided ordering operation.
Upvotes: 5