gpt4 book ai didi

c++ - shared_from_this 导致 bad_weak_ptr

转载 作者:IT老高 更新时间:2023-10-28 12:31:05 32 4
gpt4 key购买 nike

我正在尝试在 asio 中保留已连接客户端的列表。我已经从文档 (http://www.boost.org/doc/libs/1_57_0/doc/html/boost_asio/example/cpp03/chat/chat_server.cpp) 中改编了聊天服务器示例,这是我最终得到的重要部分:

#include <iostream>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>
#include <set>

using boost::asio::ip::tcp;

class tcp_connection;

std::set<boost::shared_ptr<tcp_connection>> clients;

void add_client(boost::shared_ptr<tcp_connection> client)
{
clients.insert(client);
}

class tcp_connection : public boost::enable_shared_from_this<tcp_connection>
{
public:
tcp_connection(boost::asio::io_service& io_service) : socket_(io_service)
{
}

tcp::socket socket_;

void start()
{
add_client(shared_from_this());
}

tcp::socket& socket()
{
return socket_;
}
};

class tcp_server
{
public:
tcp_server(boost::asio::io_service& io_service)
: io_service_(io_service),
acceptor_(io_service, tcp::endpoint(tcp::v4(), 6767))
{
tcp_connection* new_connection = new tcp_connection(io_service_);
acceptor_.async_accept(new_connection->socket(),
boost::bind(&tcp_server::start_accept, this, new_connection,
boost::asio::placeholders::error));
}

private:
void start_accept(tcp_connection* new_connection,
const boost::system::error_code& error)
{
if (!error)
{
new_connection->start();
new_connection = new tcp_connection(io_service_);
acceptor_.async_accept(new_connection->socket(),
boost::bind(&tcp_server::start_accept, this, new_connection,
boost::asio::placeholders::error));
}
}

boost::asio::io_service& io_service_;
tcp::acceptor acceptor_;
};

int main()
{
try
{
boost::asio::io_service io_service;
tcp_server server(io_service);
io_service.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}

return 0;
}

在调用 shared_from_this() 时,我的服务器崩溃并显示以下消息:

Exception: tr1::bad_weak_ptr

我进行了一些搜索,似乎 shared_from_this() 非常特别,但我似乎无法找到我需要更改的确切内容。

最佳答案

John Zwinck 的基本分析如下:

The bug is that you're using shared_from_this() on an object which has no shared_ptr pointing to it. This violates a precondition of shared_from_this(), namely that at least one shared_ptr must already have been created (and still exist) pointing to this.

然而,他的建议在 Asio 代码中似乎完全题外话和危险。

你应该通过——实际上——不处理指向 tcp_connection 的原始指针来解决这个问题。首先但总是使用shared_ptr而是。

boost::bind具有绑定(bind)到 shared_ptr<> 的令人敬畏的功能很好,所以只要对它进行一些异步操作,它就会自动使指向的对象保持事件状态。

这 - 在您的示例代码中 - 意味着您不需要 clients vector ,与约翰的回答相反:

void start_accept()
{
tcp_connection::sptr new_connection = boost::make_shared<tcp_connection>(io_service_);
acceptor_.async_accept(new_connection->socket(),
boost::bind(
&tcp_server::handle_accept,
this, new_connection, asio::placeholders::error
)
);
}

void handle_accept(tcp_connection::sptr client, boost::system::error_code const& error)
{
if (!error)
{
client->start();
start_accept();
}
}

我已经包含了一个样本,它使 tcp_connection做一些琐碎的工作(它每秒循环向客户端写入“hello world”,直到客户端断开连接。当它这样做时,您可以看到 tcp_connection 操作的析构函数正在运行:

Live On Coliru

#include <iostream>
#include <boost/bind.hpp>
#include <boost/make_shared.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>
#include <boost/thread.hpp>

namespace asio = boost::asio;
using asio::ip::tcp;

class tcp_connection : public boost::enable_shared_from_this<tcp_connection>
{
public:
typedef boost::shared_ptr<tcp_connection> sptr;

tcp_connection(asio::io_service& io_service) : socket_(io_service), timer_(io_service)
{
}

void start()
{
std::cout << "Created tcp_connection session\n";

// post some work bound to this object; if you don't, the client gets
// 'garbage collected' as the ref count goes to zero
do_hello();
}

~tcp_connection() {
std::cout << "Destroyed tcp_connection\n";
}

tcp::socket& socket()
{
return socket_;
}

private:
tcp::socket socket_;
asio::deadline_timer timer_;

void do_hello(boost::system::error_code const& ec = {}) {
if (!ec) {
asio::async_write(socket_, asio::buffer("Hello world\n"),
boost::bind(&tcp_connection::handle_written, shared_from_this(), asio::placeholders::error, asio::placeholders::bytes_transferred)
);
}
}

void handle_written(boost::system::error_code const& ec, size_t /*bytes_transferred*/) {
if (!ec) {
timer_.expires_from_now(boost::posix_time::seconds(1));
timer_.async_wait(boost::bind(&tcp_connection::do_hello, shared_from_this(), asio::placeholders::error));
}
}
};

class tcp_server
{
public:
tcp_server(asio::io_service& io_service)
: io_service_(io_service),
acceptor_(io_service, tcp::endpoint(tcp::v4(), 6767))
{
start_accept();
}

private:
void start_accept()
{
tcp_connection::sptr new_connection = boost::make_shared<tcp_connection>(io_service_);
acceptor_.async_accept(new_connection->socket(),
boost::bind(
&tcp_server::handle_accept,
this, new_connection, asio::placeholders::error
)
);
}

void handle_accept(tcp_connection::sptr client, boost::system::error_code const& error)
{
if (!error)
{
client->start();
start_accept();
}
}

asio::io_service& io_service_;
tcp::acceptor acceptor_;
};

int main()
{
try
{
asio::io_service io_service;
tcp_server server(io_service);

boost::thread(boost::bind(&asio::io_service::run, &io_service)).detach();

boost::this_thread::sleep_for(boost::chrono::seconds(4));
io_service.stop();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
}

典型输出:

sehe@desktop:/tmp$ time (./test& (for a in {1..4}; do nc 127.0.0.1 6767& done | nl&); sleep 2; killall nc; wait)
Created tcp_connection session
Created tcp_connection session
1 Hello world
Created tcp_connection session
2 Hello world
Created tcp_connection session
3 Hello world
4 Hello world
5 Hello world
6 Hello world
7 Hello world
8 Hello world
9 Hello world
10 Hello world
11 Hello world
12 Hello world
13
Destroyed tcp_connection
Destroyed tcp_connection
Destroyed tcp_connection
Destroyed tcp_connection
Destroyed tcp_connection

real 0m4.003s
user 0m0.000s
sys 0m0.015s

关于c++ - shared_from_this 导致 bad_weak_ptr,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27697973/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com