C ++私有访问其他类的成员

时间:2012-01-25 02:53:43

标签: c++ multithreading boost boost-asio boost-thread

我正在使用boost::asio(用于套接字),boost::thread(用于线程),libconfig++(用于配置文件读取)和protocol buffers编写多线程服务器(用于协议实现)。

服务器遵循或多或少的路线:main() - >创建一个Application对象 - >运行应用程序对象应用程序加载配置文件,然后创建服务器对象(将配置类作为const传递)。服务器对象自行配置并绑定端口,开始接受,等等。每当检测到新客户端时,服务器都会创建一个新的Client对象,然后创建一个运行客户端连接处理程序的线程。

所有这些都是为了解释配置文件是从我的Application类加载的,然后一直传递到我的Client类。如果libconfig对象一直直接传递给Client,这不应该造成任何麻烦,但众所周知,多线程意味着当两个或多个线程同时访问时内存会损坏。

The way to solve this was discussed in other post最终实现了一个自动解决互斥问题的包装器。

神奇的课程

app_config.h

#ifndef _APP_CONFIG_H_
#define _APP_CONFIG_H_ 1

#include <boost/shared_ptr.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/locks.hpp>
#include <boost/noncopyable.hpp>
#include <libconfig.h++>
#include <string>

namespace BBCP {
    namespace App {

class ConfigLock;

class Config {
public:
    friend class BBCP::App::ConfigLock;

    Config(std::string const &file) :
        cfg(new libconfig::Config()),
        mutex(new boost::mutex())
    {
        cfg->readFile(file.c_str());
    }

private:
    boost::shared_ptr<libconfig::Config> cfg;
    boost::shared_ptr<boost::mutex> mutex;
};

class Server;
class Client;

class ConfigLock : boost::noncopyable {
public:
    ConfigLock(BBCP::App::Config const &wrapper) :
        cfg(wrapper.cfg),
        mutex(wrapper.mutex),
        lock(new LockType(*mutex))
    { }

    libconfig::Config &get() throw() { return *cfg; };
private:
    boost::shared_ptr<libconfig::Config> cfg;
    boost::shared_ptr<boost::mutex> mutex;

    typedef boost::lock_guard<boost::mutex> LockType;
    boost::shared_ptr<LockType> lock;
};

    }
}

#endif

对于懒惰的人来说,这个班级包含......好吧,两个班级(具有讽刺意味的?):BBCP::App::ConfigBBCP::App::ConfigLockBBCP::App::Config只是加载文件,而BBCP::App::ConfigLockBBCP::App::Config作为参数,然后锁定BBCP::App::Config的互斥锁。一旦创建了锁,就会调用BBCP::App::ConfigLock::get,它会返回对libconfig::Config对象的引用!。

问题

好:

server.cpp:

void BBCP::App::Server::startAccept() {
    newClient.reset(new BBCP::App::Client(io_service, config_wrapper));
    acceptor.async_accept(newClient->getSocket(), boost::bind(&BBCP::App::Server::acceptHandler, this, boost::asio::placeholders::error));
}

此函数创建一个新的客户端对象,加载了boost::asio::io_service对象和BBCP::App::Config对象。

server.cpp

void BBCP::App::Server::acceptHandler(boost::system::error_code const &e) {
    if (!acceptor.is_open()) {
        // ARR ERROR!
        return;
    }

    if (!e) {
        client_pool.create_thread(*newClient);
    }
    else {
        // HANDLE ME ERROR
        throw;
    }

    startAccept();
}

此函数在......好的情况下创建一个新线程或(尚未实现)错误,然后再次启动接受循环。

在此部分之前,客户端代码通常无关紧要:

client.cpp:

void BBCP::App::Client::parseBody() {
    BBCP::Protocol::Header header;
    BBCP::Protocol::Hello hello;
    boost::scoped_ptr<BBCP::App::ConfigLock> lock;
    libconfig::Config *cfg;

    (...)

    switch ((enum BBCP::Protocol::PacketType)header.type()) {
        case BBCP::Protocol::HELLO:
            (...)

            // config_wrapper is a private variable in the client class!
            lock.reset(new BBCP::App::ConfigLock(config_wrapper));

            // ARRRRRRR HERE BE DRAGOONS!!
            *cfg = lock->get();

            (...)

            lock.reset();
            break;
        (...)

    }

    (...)
}

嗯,说实话,我没想到会出现这种错误:

/usr/include/libconfig.h++: In member function ‘void BBCP::App::Client::parseBody()’:
/usr/include/libconfig.h++:338:13: error: ‘libconfig::Config& libconfig::Config::operator=(const libconfig::Config&)’ is private
client.cpp:64:30: error: within this context
client.cpp:71:21: error: request for member ‘exists’ in ‘cfg’, which is of non-class type ‘libconfig::Config*’
client.cpp:77:51: error: request for member ‘lookup’ in ‘cfg’, which is of non-class type ‘libconfig::Config*’

但是在这里,我需要一些方法来解决它:(。我已经尝试将BBCP::App::Client作为BBCP::App::ConfigLock的朋友类,但后来就像:

In file included from ../include/app_config.h:4:0,
                 from ../include/app_main.h:6,
                 from main.cpp:18:
../include/app_client.h:15:53: error: ‘BBCP::App::Config’ has not been declared
In file included from ../include/app_config.h:4:0,
                 from ../include/app_main.h:6,
                 from main.cpp:18:
../include/app_client.h:32:5: error: ‘Config’ in namespace ‘BBCP::App’ does not name a type
In file included from ../include/app_config.h:4:0,
                 from ../include/app_main.h:6,
                 from main.cpp:18:
../include/app_client.h: In constructor ‘BBCP::App::Client::Client(boost::asio::io_service&, const int&)’:
../include/app_client.h:15:120: error: class ‘BBCP::App::Client’ does not have any field named ‘config_wrapper’

然后我就像O_O一样,所以我放弃了来到这里,再次寻找一些überC++大师hackz0r的帮助,并因为试图访问另一个班级的私人成员而犯下这样的错误。

2 个答案:

答案 0 :(得分:1)

首先要弄清楚你是否朝着正确的方向前进,下一步就是到达那里。

为什么Config类型的赋值运算符是私有的?默认情况下,编译器生成的赋值运算符是公共的,因此如果它已被声明为私有,则可能是因为没有复制对象的原因,或者您应该将其公开并且问题不再是问题

在添加好友声明之后,您的特定问题似乎表明您已经错过了包含声明/定义Config类型的标题。然后在代码中有一些错误(一个尚未定义的成员 - 上一个错误的结果?),或者在原始代码中尝试访问指针引用的对象而不解除引用它...

答案 1 :(得分:0)

您可能希望在cfg中存储指向配置对象的指针,而不是创建副本(并取消引用未初始化的指针):

cfg = &local->get();