【问题标题】:Making a header file of the Boost::Asio chat_server example gives me "one or multiple defined symbols found" error制作 Boost::Asio chat_server 示例的头文件会给我“找到一个或多个定义的符号”错误
【发布时间】:2021-05-05 20:04:39
【问题描述】:

我是 c++ 和 boost 库的新手,试图通过从这个示例中创建三个单独的文件来学习头文件。 https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/example/cpp11/chat/chat_server.cpp chat_message.hpp 在这里,虽然我不认为这会导致问题。 https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/example/cpp11/chat/chat_message.hpp

目标是将示例分成三个部分。

  1. main.cpp
  2. chat_server.h - 声明头文件
  3. chat_server.cpp - 实现

这是我的实现,但出现两个错误。

  1. 错误列表-
LNK1169 > One or more multiple defined symbols found > File-> main.exe
LNK2005 > $dummy_return@asio@boost@@YAXXZ) already defined in chat_server.obj > file-> main.obj

输出

Build started...
1>------ Build started: Project: main, Configuration: Debug Win32 ------
1>main.obj : error LNK2005: "void __cdecl boost::asio::dummy_return<void>(void)" (??$dummy_return@X@asio@boost@@YAXXZ) already defined in chat_server.obj
1>C:\Users\Offline User\source\repos\main\Debug\main.exe : fatal error LNK1169: one or more multiply defined symbols found
1>Done building project "main.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

示例代码在分成三个之前运行良好。 我不知道这是否与 typedef 或 virtual 有关,因为其他类和方法对我来说很容易理解(根据我在网上学到的)。请在这里帮助我,让我知道我在这里缺少什么?谢谢。

  1. main.cpp
#include "chat_server.h"

int main(int argc, char* argv[])
{
    try
    {
        if (argc < 2)
        {
            std::cerr << "Usage: chat_server <port> [<port> ...]\n";
            return 1;
        }

        boost::asio::io_context io_context;

        std::list<chat_server> servers;
        for (int i = 1; i < argc; ++i)
        {
            tcp::endpoint endpoint(tcp::v4(), std::atoi(argv[i]));
            servers.emplace_back(io_context, endpoint);
        }

        io_context.run();
    }
    catch (std::exception& e)
    {
        std::cerr << "Exception: " << e.what() << "\n";
    }

    return 0;
}
  1. chat_server.h
#ifndef CHAT_SERVER_H
#define CHAT_SERVER_H

#include <cstdlib>
#include <deque>
#include <iostream>
#include <list>
#include <memory>
#include <set>
#include <utility>
#include <boost/asio.hpp>
#include "chat_message.hpp"

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

//----------------------------------------------------------------------

typedef std::deque<chat_message> chat_message_queue;

//----------------------------------------------------------------------

class chat_participant
{
public:
    virtual ~chat_participant() {};
    virtual void deliver(const chat_message& msg) = 0;
};

typedef std::shared_ptr<chat_participant> chat_participant_ptr;

//----------------------------------------------------------------------

class chat_room
{
public:
    void join(chat_participant_ptr participant);

    void leave(chat_participant_ptr participant);

    void deliver(const chat_message& msg);

private:
    std::set<chat_participant_ptr> participants_;
    enum { max_recent_msgs = 100 };
    chat_message_queue recent_msgs_;
};

//----------------------------------------------------------------------

class chat_session
    : public chat_participant,
    public std::enable_shared_from_this<chat_session>
{
public:
    chat_session(tcp::socket socket, chat_room& room);

    void start();

    void deliver(const chat_message& msg);

private:
    void do_read_header();

    void do_read_body();

    void do_write();

    tcp::socket socket_;
    chat_room& room_;
    chat_message read_msg_;
    chat_message_queue write_msgs_;
};

//----------------------------------------------------------------------

class chat_server
{
public:
    chat_server(boost::asio::io_context& io_context,
        const tcp::endpoint& endpoint);
private:
    void do_accept();

    tcp::acceptor acceptor_;
    chat_room room_;
};

#endif
  1. chat_server.cpp
#include "chat_server.h"


void chat_room::join(chat_participant_ptr participant)
{
    participants_.insert(participant);
    for (auto msg : recent_msgs_)
        participant->deliver(msg);
}

void chat_room::leave(chat_participant_ptr participant)
{
    participants_.erase(participant);
}

void chat_room::deliver(const chat_message& msg)
{
    recent_msgs_.push_back(msg);
    while (recent_msgs_.size() > max_recent_msgs)
        recent_msgs_.pop_front();

    for (auto participant : participants_)
        participant->deliver(msg);
}

//----------------------------------------------------------------------
chat_session::chat_session(tcp::socket socket, chat_room& room)
    : socket_(std::move(socket)),
    room_(room)
{
}

void chat_session::start()
{
    room_.join(shared_from_this());
    do_read_header();
}

void chat_session::deliver(const chat_message& msg)
{
    bool write_in_progress = !write_msgs_.empty();
    write_msgs_.push_back(msg);
    if (!write_in_progress)
    {
        do_write();
    }
}

void chat_session::do_read_header()
{
    auto self(shared_from_this());
    boost::asio::async_read(socket_,
        boost::asio::buffer(read_msg_.data(), chat_message::header_length),
        [this, self](boost::system::error_code ec, std::size_t /*length*/)
        {
            if (!ec && read_msg_.decode_header())
            {
                do_read_body();
            }
            else
            {
                room_.leave(shared_from_this());
            }
        });
}

void chat_session::do_read_body()
{
    auto self(shared_from_this());
    boost::asio::async_read(socket_,
        boost::asio::buffer(read_msg_.body(), read_msg_.body_length()),
        [this, self](boost::system::error_code ec, std::size_t /*length*/)
        {
            if (!ec)
            {
                room_.deliver(read_msg_);
                do_read_header();
            }
            else
            {
                room_.leave(shared_from_this());
            }
        });
}

void chat_session::do_write()
{
    auto self(shared_from_this());
    boost::asio::async_write(socket_,
        boost::asio::buffer(write_msgs_.front().data(),
            write_msgs_.front().length()),
        [this, self](boost::system::error_code ec, std::size_t /*length*/)
        {
            if (!ec)
            {
                write_msgs_.pop_front();
                if (!write_msgs_.empty())
                {
                    do_write();
                }
            }
            else
            {
                room_.leave(shared_from_this());
            }
        });
}


//----------------------------------------------------------------------
chat_server::chat_server(boost::asio::io_context& io_context,
    const tcp::endpoint& endpoint)
    : acceptor_(io_context, endpoint)
{
    do_accept();
}

void chat_server::do_accept()
{
    acceptor_.async_accept(
        [this](boost::system::error_code ec, tcp::socket socket)
        {
            if (!ec)
            {
                std::make_shared<chat_session>(std::move(socket), room_)->start();
            }

            do_accept();
        });
}

【问题讨论】:

  • using namespace 应避免在头文件中,请发布完整的编译器错误输出
  • 我在您的 chat_server.h 中找不到标头后卫。你有吗,你只是不在这里显示?如果不这样做,您很可能会在链接阶段收到多个定义错误。
  • @πάνταῥεῖ 缺少包含守卫通常会从编译器而不是链接器给出多个定义错误。由于该文件在每个 cpp 文件中只包含一次,因此不会导致问题
  • @AlanBirtles 哎呀,是的。我的错。如果没有得到证明,那么很可能是 OP 的问题。
  • @AlanBirtles 我在帖子中编辑了错误列表。如果格式不对,我很抱歉。

标签: c++ sockets boost header boost-asio


【解决方案1】:

https://github.com/chriskohlhoff/asio/pull/584

include/boost/asio/impl/use_awaitable.hpp有错误,dummy_return应该标记为inline

变化:

template <>
void dummy_return()
{
}

到:

template <>
inline void dummy_return()
{
}

【讨论】:

  • 我将boost::asio::dummy_return 放入谷歌,它是最佳结果之一(实际上是this,但链接到asio PR)。将错误消息粘贴到 google(最好是来自编译器输出而不是 IDE 错误列表)通常可以解决您的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-25
  • 2011-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多