无法迭代函数返回的 non-copyable 容器
Cannot iterate on a non-copyable container returned by a function
我不确定标题,因为我不确定问题来自我容器的 "copyablility"。
我尝试了所有方法,但无法摆脱这个错误。
这是我的代码的简化版本(请不要挑战class的设计,我真的很想在BOOST_FOREACH中保留end-used语法):
template <typename T>
class MyContainer
{
public:
typedef typename std::vector<T>::iterator iterator;
typedef typename std::vector<T>::const_iterator const_iterator;
MyContainer(std::vector<T>& vec, boost::mutex& mutex) :
m_vector(vec),
m_lock(mutex)
{
}
iterator begin() { return m_vector.begin(); }
const_iterator begin() const { return m_vector.begin(); }
iterator end() { return m_vector.end(); }
const_iterator end() const { return m_vector.end(); }
private:
std::vector<T>& m_vector;
boost::lock_guard<boost::mutex> m_lock;
};
template <typename T>
struct GetContainer
{
GetContainer(std::vector<T>& vec, boost::mutex& mutex) :
m_vector(vec),
m_mutex(mutex)
{
}
MyContainer<T> Get()
{
return MyContainer<T>(m_vector, m_mutex);
}
std::vector<T>& m_vector;
boost::mutex& m_mutex;
};
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(2);
boost::mutex m;
GetContainer<int> getter(v, m);
BOOST_FOREACH(int i, getter.Get())
{
std::cout << i << std::endl;
}
return 0;
}
编译器抱怨没有 MyContainer::MyContainer(const MyContainer&) 的复制构造函数。
我也有 :
错误:没有匹配函数来调用‘MyContainer::MyContainer(boost::foreach_detail_::rvalue_probe >::value_type)’
但是,
MyContainer<T> : private boost::noncopyable
没有解决问题。
也不定义函数
boost_foreach_is_noncopyable
或专门化模板结构
is_noncopyable
for MyContainer(事实上,我如何将此模板专门化为模板类型?)
最后 "tip":
如果我从任何地方移除互斥锁和锁(我只是将向量传递给 GetContainer 和 MyContainer),它就会起作用。
但是如果我使
它不起作用
MyContainer<T> : private boost::noncopyable
(我预计它应该,所以我不确定我的问题是 BOOST_FOREACH,但也许是因为我 return MyContainer 的副本和我的 getter ?)
谢谢你读到这里,在此先感谢你的帮助。
似乎是 BOOST_FOREACH 对仅移动类型的限制。我没有找到解决它的方法¹(除了 - 丑陋 - 将 lock_guard
放在 shared_ptr
中的明显方法)。
虽然您没有指定 c++03 要求,因此您可以通过将 lock_guard
替换为 unique_lock
来使其在没有 BOOST_FOREACH 的情况下工作。
这是我对 c++11 的看法(注意它的通用性):
#include <boost/thread.hpp>
#include <boost/range.hpp>
namespace detail {
template <typename R, typename M>
struct RangeLock {
RangeLock(R&r, M& m) : _r(r), _l(m) {}
RangeLock(RangeLock&&) = default;
using iterator = typename boost::range_iterator<R>::type;
iterator begin() { using std::begin; return begin(_r); }
iterator end () { using std::end; return end (_r); }
using const_iterator = typename boost::range_iterator<R const>::type;
const_iterator begin() const { using std::begin; return begin(_r); }
const_iterator end () const { using std::end; return end (_r); }
private:
R& _r;
boost::unique_lock<M> _l;
};
}
template <typename R, typename M>
detail::RangeLock<R,M> make_range_lock(R& r, M& mx) { return {r,mx}; }
template <typename R, typename M>
detail::RangeLock<R const,M> make_range_lock(R const& r, M& mx) { return {r,mx}; }
#include <vector>
#include <map>
int main() {
boost::mutex mx;
std::vector<int> const vec { 1, 2 };
std::map<int, std::string> const map { { 1, "one" }, { 2, "two" } };
for(int i : make_range_lock(vec, mx))
std::cout << i << std::endl;
for(auto& p : make_range_lock(map, mx))
std::cout << p.second << std::endl;
for(auto& p : make_range_lock(boost::make_iterator_range(map.equal_range(1)), mx))
std::cout << p.second << std::endl;
}
版画
1
2
one
two
one
¹ 甚至没有使用 Using BOOST_FOREACH with a constant intrusive list
中的所有方法
我post我的回答如果有帮助...
使用 C++03,我终于提供了一个复制构造函数,以便能够将 class 与 BOOST_FOREACH 一起使用。
所以问题转移到另一个主题:使 class 以逻辑和适当的方式复制。
在我的例子中,我"share the lock and the vector",如果用户不想做 bug,他不应该自己使用这个副本,但是在 BOOST_FOREACH 中没关系:
- 我将互斥量更改为 recursive_mutex
我把锁换成了unique_lock
和:
MyContainer(const MyContainer& other) :
m_vector(other.vec),
m_lock(*other.m_lock.mutex())
{
}
使用 C++11
感谢 boost 邮件列表上的 Chris Glover,C++11 解决方案:
You can't do what you are trying to do in C++03. To accomplish it, you
need C++11 move semantics to be able to move the MyContainer out of the Get
function. Even without using BOOST_FOREACH, the following code fails;
GetContainer<int> getter(v, m);
MyContainer<int> c = getter.Get(); // <-- Error.
Here's an example with the necessary changes; I changed the scoped_lock to
a unique_lock and added a move constructor.
template <typename T>
class MyContainer
{
public:
[...]
MyContainer(MyContainer&& other)
: m_vector(other.m_vector)
{
m_lock = std::move(other.m_lock);
other.m_vector = nullptr;
}
我不确定标题,因为我不确定问题来自我容器的 "copyablility"。 我尝试了所有方法,但无法摆脱这个错误。
这是我的代码的简化版本(请不要挑战class的设计,我真的很想在BOOST_FOREACH中保留end-used语法):
template <typename T>
class MyContainer
{
public:
typedef typename std::vector<T>::iterator iterator;
typedef typename std::vector<T>::const_iterator const_iterator;
MyContainer(std::vector<T>& vec, boost::mutex& mutex) :
m_vector(vec),
m_lock(mutex)
{
}
iterator begin() { return m_vector.begin(); }
const_iterator begin() const { return m_vector.begin(); }
iterator end() { return m_vector.end(); }
const_iterator end() const { return m_vector.end(); }
private:
std::vector<T>& m_vector;
boost::lock_guard<boost::mutex> m_lock;
};
template <typename T>
struct GetContainer
{
GetContainer(std::vector<T>& vec, boost::mutex& mutex) :
m_vector(vec),
m_mutex(mutex)
{
}
MyContainer<T> Get()
{
return MyContainer<T>(m_vector, m_mutex);
}
std::vector<T>& m_vector;
boost::mutex& m_mutex;
};
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(2);
boost::mutex m;
GetContainer<int> getter(v, m);
BOOST_FOREACH(int i, getter.Get())
{
std::cout << i << std::endl;
}
return 0;
}
编译器抱怨没有 MyContainer::MyContainer(const MyContainer&) 的复制构造函数。 我也有 : 错误:没有匹配函数来调用‘MyContainer::MyContainer(boost::foreach_detail_::rvalue_probe >::value_type)’
但是,
MyContainer<T> : private boost::noncopyable
没有解决问题。 也不定义函数
boost_foreach_is_noncopyable
或专门化模板结构
is_noncopyable
for MyContainer(事实上,我如何将此模板专门化为模板类型?)
最后 "tip": 如果我从任何地方移除互斥锁和锁(我只是将向量传递给 GetContainer 和 MyContainer),它就会起作用。 但是如果我使
它不起作用MyContainer<T> : private boost::noncopyable
(我预计它应该,所以我不确定我的问题是 BOOST_FOREACH,但也许是因为我 return MyContainer 的副本和我的 getter ?)
谢谢你读到这里,在此先感谢你的帮助。
似乎是 BOOST_FOREACH 对仅移动类型的限制。我没有找到解决它的方法¹(除了 - 丑陋 - 将 lock_guard
放在 shared_ptr
中的明显方法)。
虽然您没有指定 c++03 要求,因此您可以通过将 lock_guard
替换为 unique_lock
来使其在没有 BOOST_FOREACH 的情况下工作。
这是我对 c++11 的看法(注意它的通用性):
#include <boost/thread.hpp>
#include <boost/range.hpp>
namespace detail {
template <typename R, typename M>
struct RangeLock {
RangeLock(R&r, M& m) : _r(r), _l(m) {}
RangeLock(RangeLock&&) = default;
using iterator = typename boost::range_iterator<R>::type;
iterator begin() { using std::begin; return begin(_r); }
iterator end () { using std::end; return end (_r); }
using const_iterator = typename boost::range_iterator<R const>::type;
const_iterator begin() const { using std::begin; return begin(_r); }
const_iterator end () const { using std::end; return end (_r); }
private:
R& _r;
boost::unique_lock<M> _l;
};
}
template <typename R, typename M>
detail::RangeLock<R,M> make_range_lock(R& r, M& mx) { return {r,mx}; }
template <typename R, typename M>
detail::RangeLock<R const,M> make_range_lock(R const& r, M& mx) { return {r,mx}; }
#include <vector>
#include <map>
int main() {
boost::mutex mx;
std::vector<int> const vec { 1, 2 };
std::map<int, std::string> const map { { 1, "one" }, { 2, "two" } };
for(int i : make_range_lock(vec, mx))
std::cout << i << std::endl;
for(auto& p : make_range_lock(map, mx))
std::cout << p.second << std::endl;
for(auto& p : make_range_lock(boost::make_iterator_range(map.equal_range(1)), mx))
std::cout << p.second << std::endl;
}
版画
1
2
one
two
one
¹ 甚至没有使用 Using BOOST_FOREACH with a constant intrusive list
中的所有方法我post我的回答如果有帮助...
使用 C++03,我终于提供了一个复制构造函数,以便能够将 class 与 BOOST_FOREACH 一起使用。 所以问题转移到另一个主题:使 class 以逻辑和适当的方式复制。
在我的例子中,我"share the lock and the vector",如果用户不想做 bug,他不应该自己使用这个副本,但是在 BOOST_FOREACH 中没关系:
- 我将互斥量更改为 recursive_mutex
我把锁换成了unique_lock 和:
MyContainer(const MyContainer& other) : m_vector(other.vec), m_lock(*other.m_lock.mutex()) { }
使用 C++11
感谢 boost 邮件列表上的 Chris Glover,C++11 解决方案:
You can't do what you are trying to do in C++03. To accomplish it, you need C++11 move semantics to be able to move the MyContainer out of the Get function. Even without using BOOST_FOREACH, the following code fails;
GetContainer<int> getter(v, m); MyContainer<int> c = getter.Get(); // <-- Error.
Here's an example with the necessary changes; I changed the scoped_lock to a unique_lock and added a move constructor.
template <typename T> class MyContainer { public: [...] MyContainer(MyContainer&& other) : m_vector(other.m_vector) { m_lock = std::move(other.m_lock); other.m_vector = nullptr; }