如何使用shared_ptr确保指针存在?

时间:2013-12-28 19:09:03

标签: c++ c++11 boost-asio shared-ptr

我正在尝试使用Boost::asio开发一个程序。这是我用来执行async_write()

的方法
template<typename T>
void Write(shared_ptr<std::vector<T>> data){
    std::cout << "Write Method [std::vector]" << std::endl;

    ioService.post(boost::bind(&TCPClient::DoWrite<T>, this, data));
}

然后,调用DoWrite()方法实际发送向量中的数据:

template<typename T>
void DoWrite(shared_ptr<std::vector<T>> data){
std::cout << "DoWrite Method [std::vector]" << std::endl;

boost::asio::async_write(   socket_,
                            boost::asio::buffer(*data),
                            boost::bind(&TCPClient::handle_write,
                            this, boost::asio::placeholders::error,
                            boost::asio::placeholders::bytes_transferred)
                        );
std::cout << "async_write executed" << std::endl;

}

但是在运行时我遇到了这个错误:

  

程序:C:\ Windows \ SYSTEM32 \ MSVCP120D.dll文件:C:\ Program Files   (x86)\ Microsoft Visual Studio 12.0 \ VC \ include \ vector Line:72

     

Expression:vector iterator not dereferencable

调查后我知道问题是传递给方法的std::vector<T>不能保持足够活动,当写入发生时(因为它是异步的),向量不存在,所以我得到了这个错误。

我知道问题是因为如果我删除template并且我的功能现在是这样的:

void DoWrite(std::vector<char> data){
    std::cout << "DoWrite Method [std::vector]" << std::endl;

    backupVector = data;

    boost::asio::async_write(   socket_,
                                boost::asio::buffer(backupVector),
                                boost::bind(&TCPClient::handle_write,
                                this, boost::asio::placeholders::error,
                                boost::asio::placeholders::bytes_transferred)
                            );
    std::cout << "async_write executed" << std::endl;
}

如果backupVectorstd::vector<char>在类中,我没有收到错误,因为我有一个存在的引用,但我无法在运行时创建std::vector<T>来存储传入在课堂上的向量(我是对的?我是C ++的新手)。 所以我读到了shared_ptr

  

std :: shared_ptr是一个保留共享所有权的智能指针   通过指针对象。几个shared_ptr对象可能拥有相同的内容   宾语。当任何一个对象被破坏并且其内存被释放时   发生以下情况:

     
      
  • 拥有该对象的最后剩余的shared_ptr将被销毁。

  •   
  • 拥有该对象的最后一个shared_ptr通过operator =或reset()分配另一个指针。

  •   

所以,如果我将指针传递给async_write,为什么它被“销毁”,如果一个对象有引用它?还有其他办法吗?

这就是我使用Write()方法的方法:

std::vector<char> data;
data.push_back('B');
data.push_back(bValue);

client.Write<char>(make_shared<std::vector<char>>(data));

Sleep(100000);

2 个答案:

答案 0 :(得分:2)

我远远无法告诉你应该在这里做什么(缺少信息,只使用asio几次),但从this example猜测,你应该能够使用类似于:

的自定义缓冲区类来传递缓冲区
// based on http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/example/cpp11/buffers/reference_counted.cpp
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

template<class T>
class shared_const_buffer
{
public:
  // Construct from a `shared_ptr`
  explicit shared_const_buffer(std::shared_ptr<std::vector<T>> const& p_data)
    : data_(p_data),
      buffer_(boost::asio::buffer(*data_))
  {}

  // Implement the ConstBufferSequence requirements.
  using value_type = boost::asio::const_buffer;
  using const_iterator = boost::asio::const_buffer const*;

  boost::asio::const_buffer const* begin() const { return &buffer_; }
  boost::asio::const_buffer const* end() const { return &buffer_ + 1; }

private:
  std::shared_ptr<std::vector<T>> data_;
  boost::asio::const_buffer buffer_;
};

正如我对这个问题的评论中提到的,我知道是否传递共享缓冲区以进行发送(写入)是一个好主意。


这是如何运作的:

在write函数中,传入一个缓冲区:

boost::asio::async_write(   socket_,
                            boost::asio::buffer(backupVector), /*...*/ );

在此示例中,缓冲区是通过boost::asio::buffer函数创建的。但是这个函数不会获取(并且不共享)参数的所有权,它只存储引用/指针。传递的缓冲区对象被复制到套接字(在作业队列中),直到作业完成为止。

通过使用shared_const_buffer而不是boost::asio::buffer创建的缓冲区对象,我们将向量的生命周期延长到创建的shared_const_buffer对象的生命周期。因此,向量至少存在,直到工作完成。

请参阅the documentation of async_writethe documentation of the buffer function / buffer invalidation

答案 1 :(得分:0)

只要执行Clint.write(...),对shared_ptr的引用就会存在。

如果你在这个参数之外声明它,它会活着更久,你的程序可能会工作。

你必须确保它保持足够长的时间,以便被boost :: asio称为函数异步写入。