C ++ закрытый доступ к членам других классов - PullRequest
1 голос
/ 25 января 2012

Я пишу многопоточный сервер, используя boost :: asio (для сокетов), boost :: thread (для потоков), libconfig ++ (для чтения файлов конфигурации) и буферы протокола (для реализации протокола).

Сервер более или менее следует по этому маршруту: main () -> создает объект Application -> запускает приложениеобъект.Приложение загружает файл конфигурации, затем создает объект сервера (которому передается класс конфигурации как const).Объект сервера настраивает себя и связывает порт, начинает принимать, бла.Каждый раз, когда обнаруживается новый клиент, сервер создает новый объект Client, а затем создает поток, выполняющий обработчик соединения клиента.

Все это объясняет, что файл конфигурации загружен из моего класса Application, изатем прошел весь путь до моего класса Client.Это не должно создавать никаких проблем, если объект libconfig был передан непосредственно клиенту, но, как мы все знаем, многопоточность подразумевает, что память повреждается при одновременном доступе двух или более потоков.

Способ решения этой проблемы обсуждался в другом посте , и в итоге была реализована оболочка, которая автоматически решает проблему мьютекса.

Магический класс

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::Config и BBCP::App::ConfigLock.BBCP::App::Config просто загружает файл, в то время как BBCP::App::ConfigLock принимает BBCP::App::Config в качестве аргумента, а затем блокирует мьютекс BBCP::App::Config.После создания блокировки вызывается BBCP::App::ConfigLock::get, который возвращает ссылку на объект libconfig::Config!.

Проблема

Well:

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();
}

ThisФункция создает новый поток или (еще не реализовано) ошибки в случае ... ну, ошибок, а затем снова запускает цикл принятия.

Код клиента в основном не имеет значения до этой части:

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, так что я просто сдался ипришел сюда, еще раз в поисках помощи какого-нибудь гуру из C ++ гуру über и ругает за совершение такого проступка, как попытка получить доступ к закрытым членам другого класса.

Ответы [ 2 ]

1 голос
/ 25 января 2012

Первое, что нужно выяснить, если вы идете в правильном направлении, и следующий шаг - это достижение.

Почему оператор присваивания типа Config закрыт? По умолчанию сгенерированный компилятором оператор присваивания является общедоступным, поэтому, если он был объявлен как закрытый, есть вероятность, что существует причина, по которой объект не будет скопирован, иначе вы должны сделать его общедоступным, и проблема больше не будет проблемой .

Что касается вашей конкретной проблемы после добавления объявления о дружбе, кажется, это означает, что вы пропустили, включая заголовок, в котором тип Config объявлен / определен. А затем в коде есть еще несколько ошибок (элемент, который не был определен - результат предыдущей ошибки?) Или в исходном коде, пытающемся получить доступ к объекту, на который указывает указатель, без разыменования его ...

0 голосов
/ 25 января 2012

Возможно, вы хотите сохранить указатель на объект конфигурации в cfg вместо создания копии (и разыменования неинициализированного указателя):

cfg = &local->get();
...