Why stl vector can't contain coroutine objects? - c++

I use coroutine in boost1.53, see my code below:
boost::coroutines::coroutine<int()> f(std::bind(foo, ...));
std::vector<decltype(f)> container; // it can be compiled
container.push_back(f); // compile error
the error:
no matching function for call to ‘std::vector<boost::coroutines::coroutine<int(),0> >::vector(paracel::coroutine<int>&)’
Update: The error is occured because there are no copy construction/operator in 'boost::coroutines::coroutine', case here is I only want to save the 'f's into a container which map a index to 'f'.
I also tried unordered_map, and emplace_back, it still can not work!
How can I make it work in C++?
Update2:
I tried vector,unordered_map, map together with emplace_back, push_back, std::move and all failed.
But list and deque is ok with push_back/emplace_back and std::move:
std::deque<decltype(f)> container1;
container.push_back(std::move(f)); // ok
std::deque<decltype(f)> container2;
container.emplace_back(std::move(f)); // ok
std::list<decltype(f)> container3;
container.push_back(std::move(f)); // ok
std::list<decltype(f)> container4;
container.emplace_back(std::move(f)); // ok
Why?

It looks as if boost::coroutines::coroutines<int()> doesn't support a copy constructor. You try to push_back() an lvalue, however. You might want to try moving the object into vector, though:
container.push_back(std::move(f));

If you check e.g. this reference you will see that the contained type
T must meet the requirements of CopyAssignable and CopyConstructible.
And
The requirements that are imposed on the elements depend on the actual operations performed on the container. Generally, it is required that element type meets the requirements of MoveConstructible and MoveAssignable, but many member functions impose stricter requirements.
If you check the coroutine class you will see that it has neither copy-assignment operator nor a copy-constructor. It do have move variants of those, but as noted by the second paragraph above, it's not always enough.

I use Boost 1.54 and it works for me with both g++4.8.2 and clang-3.4 with libc++:
#include <iostream>
#include <vector>
#include <boost/coroutine/coroutine.hpp>
typedef boost::coroutines::coroutine<int()> coro_t;
void f(coro_t::caller_type& ca)
{
ca(42);
}
int main()
{
std::vector<coro_t> coros;
coro_t foo(&f);
coros.push_back(std::move(foo));
coros.emplace_back(&f);
for(auto& coro : coros)
std::cout << coro.get() << std::endl;
}
I'm going to speculate that you don't have a working standard library or the move assignment in coroutine of boost 1.53 is not noexcept (you can check that with std::is_nothrow_move_assignable).

two possibilities:
1.) allocate the coroutines on freestore:
std::vector< shared_ptr< coroutine< void >::pull_type > v;
v.push_back( new coroutine< void >::pull_type(...) );
2.) use a moveaware-container (boost.container):
boost::container::vector< coroutine< void >::pull_type > v;
coroutine< void >::pull_type c(...)
v.push_back( boost::move( c) );

Related

How to create a reference to any class implementing square bracket operator?

I use std::vector<double> in some of my logic, but mainly the operator[]. Some data is coming from google's protocol buffer library in a repeated field. An example for the proto file:
message My_message{
repeated double numbers = 1;
}
So far I've only been using vectors, and converted the protobuf field to vector as described in another question.
void my_function(const std::vector<double> my_numbers){
...
double i_shall_copy_this = my_numbers[0];
std::copy(my_numbers.begin(),my_numbers.end(), inside_vector.begin());
...
}
int main(){
My_message my_msg;
...
std::vector<double> my_vec = {my_msg.numbers().begin(),my_msg.numbers().end()};
my_function(my_vec);
return 0;
}
Unfortunately this comes with unnecessary copying of data, which I would like to avoid. To avoid copying I would like to use references.
void my_function(const std::vector<double>& my_numbers){
...
}
int main(){
My_message my_msg;
...
my_function({my_msg.numbers().begin(),my_msg.numbers().end()}); //(1)
my_function(reinterpret_cast<std::vector<double>>(my_msg.numbers())); //(2)
return 0;
}
So far, adding it by temporary works( //(1) ), but it involves copying.
Despite the fact that both google::protobuf::RepeatedField and std::vecDor implements operator[], a reinterpret cast have failed //(2) :
error: invalid cast from type ‘const google::protobuf::RepeatedField<double>’ to type ‘std::vector<double>’
So a solution I have been thinking about is to add a third type, which requires only operator[] and the iterators implemented ( and a contiguous guarantee ).
Unfortunately common inheritance is not an option here: Both types come from official libraries, and I am just a mortal unworthy of maintaining a fork of those for a project. What options do I have here?
This is what templates are for. Since you only need the passed in type to have an operator[], you can make the function a template:
template<typename Container>
void my_function(const Container & my_numbers) {
// use my_numbers[42] for example
}
and now this will compile for any type that has operator[] defined for it.
So now there is no need to convert the google::protobuf::RepeatedField<double> to a temporary std::vector<double>.

Why boost intrusive list 's push_back function requires lvalue?

I am learning intrusive list:
#include <iostream>
#include <list>
#include <boost/intrusive/list.hpp>
struct DummyObject : public boost::intrusive::list_base_hook<>{
double price;
DummyObject(const double a): price(a){
}
};
using IntrusiveListContainer = boost::intrusive::list<DummyObject>;
using NonintrusiveListContainer = std::list<DummyObject>;
int main()
{
IntrusiveListContainer intrusivecontainer;
NonintrusiveListContainer nonintrusivecontainer;
intrusivecontainer.push_back(DummyObject (22.2)); // ERROR
nonintrusivecontainer.push_back(DummyObject (22.2));// compiled
return 0;
}
I understand the basic idea of intrusive list, but I cannot understand why push_back requires lvalue specifically. From a logic perspective, why intrusive list cannot cope with rvalue ?
Does lvalue requirement imply that, the user need to handle the life-circle of DummyObject by himself? In other word, when IntrusiveList pop_front, the pop-ed object will not be destructed ?
Also, event I pass by lvalue:
int main()
{
IntrusiveListContainer intrusivecontainer;
NonintrusiveListContainer nonintrusivecontainer;
DummyObject a(22.2);
intrusivecontainer.push_front(a); // compiled
//nonintrusivecontainer.push_back(DummyObject (22.2));// compiled
return 0;
}
the binary failed one of the assert:
intrusivelist: /usr/include/boost/intrusive/detail/generic_hook.hpp:48: void boost::intrusive::detail::destructor_impl(Hook&, boost::intrusive::detail::link_dispatch<(boost::intrusive::link_mode_type)1>) [with Hook = boost::intrusive::generic_hook<(boost::intrusive::algo_types)0, boost::intrusive::list_node_traits, boost::intrusive::dft_tag, (boost::intrusive::link_mode_type)1, (boost::intrusive::base_hook_type)1>]: Assertion `!hook.is_linked()' failed.
This is simple intrusive container doesn't perform memory management. It is your responsibility to ensure that stored object outlives intrusive container.
This is point out in documentation:
Intrusive and non-intrusive containers - 1.64.0
The user has to manage the lifetime of inserted objects independently from the containers.
Now temporary object will live shorter then intrusive container leading to undefined behavior, intrusive container do not create any copy. so use of r-value is not desired.
Now this version of your example works fine (no crash):
int main()
{
DummyObject a(22.2);
IntrusiveListContainer intrusivecontainer;
NonintrusiveListContainer nonintrusivecontainer;
intrusivecontainer.push_back(a); // ERROR
nonintrusivecontainer.push_back(a);// compiled
return 0;
}
And on other hand this version ends with assertion failure:
int main()
{
IntrusiveListContainer intrusivecontainer;
NonintrusiveListContainer nonintrusivecontainer;
DummyObject a(22.2);
intrusivecontainer.push_back(a); // ERROR
nonintrusivecontainer.push_back(a);// compiled
return 0;
}
I had the same assertion fail when working with intrusive lists, even when using lvalue.The assert fail will happen if the list is not empty when destroyed.
If you pop() all the values before the list destructor is called, should be ok.

Calling std::lock () with std::vector <mutex*>

I would like to replace the following code with std::lock():
for (mutex* m : mutexes) {
m->lock();
}
Is there anyway I could invoke std::lock () on those mutexes given a std::vector<mutex*>?
Unfortunately the standard library doesn't provide an overload for std::lock that takes a pair of iterators pointing to lockable objects. To use std::lock you must know the number of lockable objects at compile time, and pass them as arguments to the function. However, Boost does provide an overload that takes iterators, and it'll work with std::mutex.
The other piece of scaffolding you'll need is boost::indirect_iterator; this will apply an extra dereference when you dereference the iterator (needed because you have std::vector<std::mutex*> and not std::vector<std::mutex>. The latter would not be very useful anyway since std::mutex cannot be copied or moved.)
#include <boost/thread/locks.hpp>
#include <boost/iterator/indirect_iterator.hpp>
#include <vector>
#include <mutex>
int main()
{
using mutex_list = std::vector<std::mutex*>;
mutex_list mutexes;
boost::indirect_iterator<mutex_list::iterator> first(mutexes.begin()),
last(mutexes.end());
boost::lock(first, last);
}
Live demo

'auto_ptr' and STL containers: writing an example of erroneous usage

This question raised after reading this tutorial:
http://www.cprogramming.com/tutorial/auto_ptr.html
There you can find the following statement: A subtle consequence of this behavior is that auto_ ptrs don't work well in all scenarios. For instance, using auto _ptr objects with the standard template library can lead to problems as some functions in the STL may make copies of the objects in containers such as the vector container class. One example is the sort function, which makes copies of some of the objects in the container being sorted. As a consequence, this copy can blithely delete the data in the container!
Most of the papers concerning 'auto_ptr' tell us something like following:
"Never use 'auto_ptr' with STL containers! They often copy their elements while performing intrinsic operations. For example consider sort on std::vector".
So my goal is to write the code sample that illustrates this point or prove that such examples are only theoretically true and weird on practice.
P.S. #everybody_who_also_knows_that_auto_ptr_is_deprecated
I also know this. But don't you consider technical reasons (legacy code or old compiler) that may not allow new pointer containers usage? And moreover this question is about old and bad (if you'd like) auto_ptr.
I don't have MSVC right now, but judging from the error from g++, I guess this is the reason:
auto_ptr<T> only has a "copy constructor" which takes mutable references (§D.10.1.1[auto.ptr.cons]/2­–6):
auto_ptr(auto_ptr& a) throw();
template<class Y> auto_ptr(auto_ptr<Y>& a) throw();
But vector::push_back will accept a const reference (§23.3.6.1[vector.overview]/2).
void push_back(const T& x);
So it is impossible to construct an auto_ptr via push_back because no constructor takes a const reference.
From what you write, it seems that you already know everything that there is to know about containers of auto_ptrs and why they are unsafe.
Therefore, I assume that your interest in containers of auto_ptrs is purely teaching oriented. I understand your frustration in attempting to build a deliberate counter-example: in fact, most implementers of standard containers have put in place work-arounds to avoid accidentally triggering the broken semantics of auto_ptrs.
So, here's an example that I have written myself precisely for teaching:
class MyClass {
int a;
public:
MyClass (int i) : a(i) { }
int get() const { return a; }
};
int main() {
constexpr unsigned size = 10;
std::vector< std::auto_ptr<MyClass> > coap;
coap.resize(size);
for (unsigned u=0; u<size; u++)
coap[u] = std::auto_ptr<MyClass>( new MyClass( rand() % 50 ));
std::sort( coap.begin(), coap.end(),
[]( std::auto_ptr<MyClass> a,
std::auto_ptr<MyClass> b) { return a->get() < b->get(); });
}
Compiling it with g++ 4.9.2 will lead to an executable that will segfault nicely.
You can rewrite the example above even more concisely by using type deduction:
std::sort( coap.begin(), coap.end(),
[]( auto a, auto b) { return a->get() < b->get(); });
Note that the problem is not in the specific implementation of std::sort, which seems to be auto_ptr-safe. It is rather in the comparison lambda function I am passing to std::sort, that deliberately accepts its arguments by value, thus destroying the objects in the container every time a comparison is performed.
If you changed the lambda so that it receives its arguments by reference, as shown below, most STL implementations would actually behave correctly, even if you are doing something that is conceptually wrong.
std::sort( coap.begin(), coap.end(),
[]( const std::auto_ptr<MyClass> & a,
const std::auto_ptr<MyClass> & b) { return a->get() < b->get(); });
Good luck!
STEP 1
Lets' solve this problem in a straight way:
#include <iostream>
#include <vector>
#include <algorithm>
template<> struct std::less<std::auto_ptr<int>>: public std::binary_function<std::auto_ptr<int>, std::auto_ptr<int>, bool> {
bool operator()(const std::auto_ptr<int>& _Left, const std::auto_ptr<int>& _Right) const
{ // apply operator< to operands
return *_Left < *_Right;
}
};
int wmain() {
using namespace std;
auto_ptr<int> apai(new int(1)), apai2(new int(2)), apai3(new int(3));
vector<auto_ptr<int>> vec;
vec.push_back(apai3);
vec.push_back(apai);
vec.push_back(apai2);
for ( vector<auto_ptr<int>>::const_iterator i(vec.cbegin()) ; i != vec.cend() ; ++i )
wcout << i->get() << L'\t';
vector<int> vec2;
vec2.push_back(3);
vec2.push_back(2);
vec2.push_back(5);
sort(vec2.begin(), vec2.end(), less<int>());
sort(vec.begin(), vec.end(), less<auto_ptr<int>>());
return 0;
}
On MSVCPP11 the error text is following:
_Error 1 error C2558: class 'std::auto_ptr<Ty>': no copy constructor available or copy constructor is declared 'explicit' c:\program files (x86)\microsoft visual studio 11.0\vc\include\xmemory0 608
The conclusion is: I even cannot compile such example. Why do they prevent me to do something that I cannot compile?? Their preventions are not always true.
STEP 2
We cannot use auto_ptr as vector element type directly due to auto_ptr design. But we can wrap `auto_ptr' in the way presented below.
#include <iostream>
#include <vector>
#include <algorithm>
#include <memory>
#include <functional>
template<typename T> class auto_ptr_my: public std::auto_ptr<T> {
public:
explicit auto_ptr_my(T *ptr = 0) {
this->reset(ptr);
}
auto_ptr_my<T> &operator=(const auto_ptr_my<T> &right) {
*(static_cast<std::auto_ptr<T> *>(this)) = *(static_cast<std::auto_ptr<T> *>(const_cast<auto_ptr_my *>(&right)));
return *this;
}
auto_ptr_my(const auto_ptr_my<T>& right) {
*this = right;
}
};
namespace std
{
template<> struct less<auto_ptr_my<int> >: public std::binary_function<auto_ptr_my<int>, auto_ptr_my<int>, bool> {
bool operator()(const auto_ptr_my<int>& _Left, const auto_ptr_my<int>& _Right) const
{ // apply operator< to operands
return *_Left < *_Right;
}
};
}
int wmain() {
using namespace std;
auto_ptr_my<int> apai(new int(1)), apai2(new int(2)), apai3(new int(3));
vector<auto_ptr_my<int>> vec;
vec.push_back(apai3);
vec.push_back(apai);
vec.push_back(apai2);
for ( vector<auto_ptr_my<int>>::const_iterator i(vec.cbegin()) ; i != vec.cend() ; ++i )
wcout << **i << L'\t';
sort(vec.begin(), vec.end(), less<auto_ptr_my<int>>());
for ( vector<auto_ptr_my<int>>::const_iterator i(vec.cbegin()) ; i != vec.cend() ; ++i )
wcout << **i << L'\t';
return 0;
}
This code works well showing that auto_ptr can be used with vector and sort with no memory leaks and crashes.
STEP 3
As KennyTM posted below:
add this code before return 0; statement:
std::vector<auto_ptr_my<int>> vec2 = vec;
for ( vector<auto_ptr_my<int>>::const_iterator i(vec2.cbegin()) ; i != vec2.cend() ; ++i )
wcout << **i << L'\t';
wcout << std::endl;
for ( vector<auto_ptr_my<int>>::const_iterator i(vec.cbegin()) ; i != vec.cend() ; ++i )
wcout << **i << L'\t';
wcout << std::endl;
...and get memory leaks!
CONCLUSION
Sometimes we can use auto_ptr with containers without visible crash, sometimes not. Anyway it is bad practice.
But don't forget that auto_ptr is designed in such way that you cannot use it straight with STL containers and algorithms: against you have to write some wrapper code. At last using auto_ptr with STL containers is for your own risk. For example, some implementations of sort will not lead to the crash while processing vector elements, but other implementations will lead directly to the crash.
This question has academic purposes.
Thanks to KennyTM for providing STEP 3 crash example!
The conclusion is: I even cannot compile such example. Why do they prevent me to do something that I cannot compile??
IIRC, it is the other way around: the compiler vendor takes steps to prevent you from compiling something that you shouldn't be able to do. The way the standard is written, they could implement the library in a way that the code compiles, and then fails to work properly. They can also implement it this way, which is seen as superior because it's one of those few times where the compiler is actually allowed to prevent you from doing something stupid :)
The right answer is "never use auto_ptr at all" -- its deprecated and never became part of the standard at all, for precisely the reasons outlined here. Use std::unique_ptr instead.

storing mem_fun in a standard container

Is there a way to create a vector< mem_fun_t< ReturnType, MyClass > > ?
The error i'm seeing is:
error C2512: 'std::mem_fun1_t<_Result,_Ty,_Arg>' : no appropriate default constructor available
I really can't see why it would not work, but it's actually a pretty ugly solution. Just take vector<function<ReturnType(MyClass*)>> and be without those issues present in C++03 binders.
You certainly can create such a vector.
#include <vector>
#include <functional>
#include <iostream>
struct MyClass
{
int a() { return 1; }
int b() { return 2; }
};
int main()
{
std::vector<std::mem_fun_t<int, MyClass> > vec;
vec.push_back(std::mem_fun(&MyClass::a));
vec.push_back(std::mem_fun(&MyClass::b));
MyClass x;
for (size_t i = 0; i != vec.size(); ++i) {
std::cout << vec[i](&x) << '\n';
}
}
If you are having problems, read the error message carefully. For example, std::mem_fun can return all sorts of wrappers, depending on what you pass to it.
Or indeed, switch to boost's or C++0x's function.
Edit: With this particular error message, I assume that you are doing something that invokes the default constructor for contained type (e.g resize or specifying the size with the vector's constructor). You can't use those functions.
mem_fun_t meets the requirements to be stored in a container (it is copy-constructible and assignable), so the answer is yes.
However, it isn't default-constructible or comparable, so there are some things you can't do with a container of them, including:
Resizing, unless you provide a value to fill with
Constructing with a non-zero size, unless you provide a value to fill with
Comparing containers
The error you are seeing comes from trying to either resize, or construct with a size.