- 01
 - 02
 - 03
 - 04
 - 05
 - 06
 - 07
 - 08
 - 09
 - 10
 - 11
 - 12
 - 13
 - 14
 - 15
 - 16
 - 17
 - 18
 - 19
 - 20
 - 21
 - 22
 - 23
 - 24
 - 25
 - 26
 - 27
 - 28
 - 29
 - 30
 - 31
 - 32
 - 33
 - 34
 - 35
 - 36
 - 37
 - 38
 - 39
 - 40
 - 41
 - 42
 - 43
 - 44
 - 45
 - 46
 - 47
 - 48
 - 49
 - 50
 - 51
 - 52
 - 53
 - 54
 - 55
 - 56
 - 57
 - 58
 - 59
 - 60
 - 61
 - 62
 - 63
 - 64
 - 65
 - 66
 - 67
 - 68
 - 69
 - 70
 - 71
 - 72
 - 73
 - 74
 - 75
 - 76
 - 77
 - 78
 - 79
 - 80
 - 81
 - 82
 - 83
 - 84
 - 85
 - 86
 - 87
 - 88
 - 89
 - 90
 - 91
 - 92
 - 93
 - 94
 - 95
 
                        #include <iostream>
#include <list>
#include <queue>
#include <memory>
#include <mutex>
#include <condition_variable>
#include <type_traits>
#include <assert.h>
using namespace std;
template<class Data>
class UnboundedQueueForNonThrowMovable
{
	static_assert(std::is_nothrow_move_constructible<Data>::value, "Data must be nonthrow movable type.");
	static_assert(!std::is_array<Data>::value, "Data must not be c-array.");
	
public:
	typedef Data value_type;
	
private:
	typedef std::queue<Data, std::list<Data>> Queue;
	typedef std::unique_lock<std::mutex> Lock;
	Queue _queue;
	std::mutex _lockQueue;
	std::condition_variable _pushToQueue;
	
	UnboundedQueueForNonThrowMovable(const UnboundedQueueForNonThrowMovable&) = delete;
	UnboundedQueueForNonThrowMovable(UnboundedQueueForNonThrowMovable&&) = delete;
	UnboundedQueueForNonThrowMovable& operator=(const UnboundedQueueForNonThrowMovable&) = delete;
	UnboundedQueueForNonThrowMovable& operator=(UnboundedQueueForNonThrowMovable&&) = delete;
public:
	UnboundedQueueForNonThrowMovable(void){}
	
	void push(Data&& data)
	{
		Lock lockerQueue(this->_lockQueue);
		this->_queue.push(std::move(data));
		this->_pushToQueue.notify_all();//_condition.notify_one(); most optimal, but can cause deadlock.
	}
	
	void push(Data& data)
	{
		this->push(std::move(data));
	}
	
	bool emptyUnstable(void) const
	{
		Lock lockerQueue(this->_lockQueue);
		return this->_queue.empty();
	}
	
	Data pop(void)
	{
		Lock lockerQueue(this->_lockQueue);
		this->_pushToQueue.wait(lockerQueue, [this](void){return !this->_queue.empty();});
		assert(!this->_queue.empty());
		Data result = std::move(this->_queue.front());
		this->_queue.pop();
		return result;
	}
	
	template< class Rep, class Period>
	Data pop(const std::chrono::duration<Rep, Period> WaitDuration)
	{
		Lock lockerQueue(this->_lockQueue);
		if(!this->_pushToQueue.wait(lockerQueue, WaitDuration, [this](void){return !this->_queue.empty();}))
			return Data();
		assert(!this->_queue.empty());
		Data result = std::move(this->_queue.front());
		this->_queue.pop();
		return result;
	}
};
template<class Data>	
using UnboundedQueueForUniquePtr = UnboundedQueueForNonThrowMovable<std::unique_ptr<Data>>;
template<class Data>
using UnboundedQueueForSharedPtr = UnboundedQueueForNonThrowMovable<std::shared_ptr<const Data>>;
template<class Data>
using UnboundedQueue = UnboundedQueueForUniquePtr<Data>;
int main() {
	cout<<"ok"<<endl;
	{
		//UnboundedQueueForSharedPtr<int>::value_type == std::shared_ptr<const int>
		UnboundedQueueForSharedPtr<int> queueSharedPtr;
		//auto a = std::make_shared<const int>(45);
		auto a = std::make_shared<int>(45);
		assert(a);
		queueSharedPtr.push(a);
		assert(!a);//Fired if you use "auto a = std::make_shared<int>(45)" below. It is compiler bug, I think, because previus code line must cause compile error.
		auto b = queueSharedPtr.pop();//std::shared_ptr<const int>
		assert(b);
		cout<<*b<<endl;
		assert(*b==45);
                                 
        
"a" (которая lvalue) магически превратиться в rvalue не может, поэтому выбираться перегрузка в queueSharedPtr.push(a); как void push(Data&& data) по идеи не должна выбираться.
std::shared_ptr<const int> a - это не константная lvalue. У нас принимается не константная ссылка на std::shared_ptr<int>.
1) Внутри неявный или явный через конструктор std::shared_ptr каст из std::shared_ptr<const T> в std::shared_ptr<T> (но не наоборот) без std::const_pointer_cast должен быть запрещен.
2) Допустим 1 провалено из-за ошибки в библиотеке в std::shared_ptr, тогда произойти каст в не константную ссылку на указатель не может и перегрузка void push(Data& data) уже выбраться не может. Похоже выбирается вместо неё void push(Data&& data) и она уже утягивает из это временной копии объект. Как эту проблему обойти не смотря на баг в компиляторе? Если он конечно имеет место. А если не имеет, то как тем более обойти эту проблему, если хочется гарантированного утягивания указателя?
Я не пробовал, но наверное если оставить только void push(Data&& data), то бага все равно останется. То есть это не поможет. Как же быть? Бага ли это вообще?
Похожих проблем с тем же std::unique_ptr нет.
Попробовать явно указать тип? push((Data&)a), или какой вы там тип ожидаете.
Осталось понять, как работает конструктор shared_ptr<int>(shared_ptr<const int>&&)
Рекомендую воспользоваться блокирующей очередью из C++ Concurrency in Action 2012
?
а перед этим попроси спецификацией завернуть детородный орган.
Ох лол. Юзай std::lock_guard.
>std::queue<Data, std::list<Data>>
Юзай std::deque. А лучше пиши BoundedQueue вместо UnboundedQueue и внутри используй boost::circular_buffer или его аналог, тк он по моему не умеет в push_back от rvalue.
>this->_pushToQueue.notify_all();
Юзай notify_one();