Подтвердить что ты не робот

Std:: thread pass by reference calls copy constructor

Ну, у меня проблема с передачей данных в поток с использованием std:: thread. Я думал, что понял общую семантику конструкторов копирования и т.д., Но, похоже, я не совсем понимаю проблему. У меня есть простой класс Log, который скрыл его конструктор копирования:

class Log
{
public:
    Log(const char filename[], const bool outputToConsole = false);
    virtual ~Log(void);

    //modify behavior
    void appendStream(std::ostream *);
    //commit a new message
    void commitStatus(const std::string str);

private:
    //members
    std::ofstream fileStream;
    std::list<std::ostream *> listOfStreams;

    //disable copy constructor and assignment operator
    Log(const Log &);
    Log & operator=(const Log &);
}

теперь у меня есть основа, основанная в основном на http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/example/cpp11/echo/blocking_tcp_echo_server.cpp

int main()
{
    static int portNumber = 10000;

    Log logger("ServerLog.txt", true);
    logger.commitStatus("Log Test String");

    try {
        boost::asio::io_service ioService;
        server(ioService, portNumber, logger);
    }
    catch (std::exception &e)
    {
        std::cerr << "Exception " << e.what() << std::endl;
        logger.commitStatus(e.what());
    }

    return 0;
}

Вы можете видеть, что основной вызов вызывает функциональный сервер и передает IOService, portNumber и logger. Регистратор передается по ссылке, таким образом:

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

void server(boost::asio::io_service &ioService, unsigned int port, Log &logger)
{
    logger.commitStatus("Server Start");

    tcp::acceptor acc(ioService, tcp::endpoint(tcp::v4(), port));

    while(true)
    {
        tcp::socket sock(ioService);
        acc.accept(sock);

        std::thread newThread(session, &sock, logger);
        newThread.detach();
    }

    logger.commitStatus("Server closed");
}

Я получаю ошибку компилятора, когда пытаюсь передать регистратор (или сокет) в поток по ссылке, но я не получаю ошибку при передаче ее в сеанс() по ссылке

static void session(tcp::socket *sock, Log &logger)
{
    std::cout << " session () " << std::endl;
}

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

ошибка C2248: 'Log:: Log': не может получить доступ к закрытому члену, объявленному в классе 'Log'

1 > \log.h(55): см. объявление "Log:: Log"

1 > \log.h(28): см. объявление "Журнал"

...

: см. ссылку на экземпляр шаблона функции 'std:: thread:: thread (_Fn, _V0_t &, _ V1_t)' компилируется

1 > с

1 > [

1 > Fn = void (_cdecl *) (boost:: asio:: ip:: tcp:: socket *, Log &),

1 > _V0_t = boost:: asio:: ip:: tcp:: socket *,

1 > _V1_t = Log &

1 > ]

Однако, если я изменяю его, чтобы передать указатель, все будет счастливым

...
        std::thread newThread(session, &sock, &logger);
...

static void session(tcp::socket *sock, Log *logger)
{
    std::cout << " session () " << std::endl;
}

Почему передача по ссылке вызывает мой конструктор копирования. Что-то особенное происходит здесь из-за std:: thread? Я неправильно понял конструктор копирования и передал ссылку?

Я получаю другую, но столь же непонятную ошибку, если попытаюсь использовать std:: move(), как это сделано в примере. Возможно ли, что мой VS2012 не реализует С++ 11 правильно?

4b9b3361

Ответ 1

std::thread принимает аргументы по значению. Вы можете вернуть ссылочную семантику с помощью std::reference_wrapper:

std::thread newThread(session, &sock, std::ref(logger));

Очевидно, вы должны убедиться, что logger переживает поток.

Ответ 2

Я получаю ошибку компилятора, когда пытаюсь передать регистратор (или сокет) в поток по ссылке

Недостаточно, чтобы функция входной точки потока принимала ссылочный тип: сам объект потока принимает свои аргументы по значению. Это происходит потому, что вы обычно хотите копировать объекты в отдельный поток.

Чтобы обойти это, вы можете передать std::ref(logger), который является ссылочной оболочкой, скрывающей ссылочную семантику под скопируемым объектом.