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

How to ensure pointer existence with shared_ptr?

本文关键字:指针 存在 确保 ptr 何使用 shared      更新时间:2023-10-16

我正在尝试使用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

表达式:矢量迭代器不可解引用

经过调查,我知道问题是传递给方法的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;
}

其中backupVector是类内的std::vector<char>,我没有得到错误,因为我有一个存在的引用,但我不能在运行时创建std::vector<T>来存储类中的传入向量(我是对的吗?我是C++的新手)。所以我读了关于shared_ptr:的文章

std::shared_ptr是一个智能指针,它保留对象。几个shared_ptr对象可能拥有相同的对象当出现以下情况之一时,对象将被销毁并释放其内存发生以下情况之一:

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

  • 通过运算符=或reset()为拥有该对象的最后一个剩余shared_ptr分配另一个指针。

那么,如果我将指针传递给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);

我还远远不能告诉应该在这里做什么(缺少信息,只使用了几次asio),但从这个例子中推测,你应该能够使用类似于的自定义缓冲区类来传递缓冲区

// 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_;
};

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


这是如何工作的:

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

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

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

通过使用shared_const_buffer而不是boost::asio::buffer创建的缓冲对象,我们将向量的生存期扩展到至少创建的shared_const_buffer对象的生存期。因此,向量至少会一直存在到作业完成为止。

请参阅async_write的文档和buffer功能/缓冲区无效的文档。

对shared_ptr的引用仅在执行Clint.write(…).时有效

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

您只需要确保它停留的时间足够长,以便由boost::asio调用的函数异步编写。