Когда из области видимости, std :: bind продлит время жизни объекта, как массив символов, если так, как это работает? - PullRequest
0 голосов
/ 06 декабря 2018

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

void test_thread_pool_arr(){

    auto lb_print = [](const char* str){
        info("print msg: %s, and i will sleep 2s", str);
        sleep(2);
    };

    ThreadPool tp(3);

    {
        char arr[10];
        memset(arr, '1', sizeof arr);
        arr[9] = '\0';

        tp.addTask(std::bind(lb_print, arr));
        tp.addTask(std::bind(lb_print, arr));
    } // leave scope so, arr should be invalid

    info("leave scope....");

    tp.exit(); // tell ThreadPool to join and then exit.
    tp.join();
    info("ending....");
}

Вывод, как показано ниже:

2018/12/06-20:07:59 leave scope....
2018/12/06-20:07:59 print msg: 111111111, and i will sleep 2s
2018/12/06-20:07:59 print msg: 111111111, and i will sleep 2s
2018/12/06-20:08:01 ending....

Я думаю, что когда arr покидает свою область, он должен быть уничтожен, но выводится нормально (целевая функция lb_print просто получает адрес arr, но arr уничтожается).

Почему?Std :: bind продлевает это время жизни?Если да, то как это работает?

Другой пример с объектом класса:

class BindScope{
    public:
        BindScope(int i=0):n_(i){
            info("BindScope ctor %d", n_);
        }

        ~BindScope(){
            info("BindScope ~dtor %d", n_);
        }

        void print()const{
            info("do print %d", n_);
        }

    int n_;
};

void test_thread_pool_scope(){
    auto lb_print = [](const BindScope& bs){
        bs.print();
    };

    ThreadPool tp(3);

    {
        BindScope bs(4);
        tp.addTask(std::bind(lb_print, std::ref(bs)));
        tp.addTask(std::bind(lb_print, std::ref(bs)));
    }// bs be destoryed, but tp do task normally

    info("out scope");
    tp.exit();
    tp.join();
    info("ending.........");
}

Вывод, как показано ниже:

2018/12/06-20:14:03 BindScope ctor 4
2018/12/06-20:14:03 BindScope ~dtor 4
2018/12/06-20:14:03 out scope
2018/12/06-20:14:03 do print 4
2018/12/06-20:14:03 do print 4
2018/12/06-20:14:03 ending.........

Мы можем видеть, что когда объект bs выходит из области видимости, его уничтожают, но ThreadPool выполняет задачу в обычном режиме.Почему?

Ответы [ 3 ]

0 голосов
/ 06 декабря 2018

На самом деле оба случая вызывают неопределенное поведение.Вы ссылаетесь на висячий указатель и висячий указатель.Все может случиться.И в некоторых случаях он может работать "нормально".

0 голосов
/ 06 декабря 2018

Да, это будет ссылка на свисающий указатель.Пример, подобный приведенному ниже:

class BindScope{
    public:
        BindScope(int i=0):n_(i){
            arr_ = new char[n_+1];
            memset(arr_, '1', n_);
            arr_[n_] = '\0';

            info("BindScope ctor %d", n_);
        }

        ~BindScope(){
            info("BindScope ~dtor %d", n_);
            delete[] arr_;
        }

        void print()const{
            info("do print %d, %s", n_, arr_);
        }

    int n_;
    char* arr_; // test for outof scope
};

void test_thread_pool_scope(){
    auto lb_print = [](const BindScope& bs){
        bs.print();
    };

    ThreadPool tp(3);

    {
        BindScope bs(4);
        bs.print();  // test for normally output.

        tp.addTask(std::bind(lb_print, std::ref(bs)));
        tp.addTask(std::bind(lb_print, std::ref(bs)));
    }  //  bs got destoryed.

    info("out scope");
    tp.exit();
    tp.join();
    info("ending.........");
}

Вывод, как показано ниже:

2018/12/06-20:36:43 BindScope ctor 4
2018/12/06-20:36:43 do print 4, 1111    // output normal
2018/12/06-20:36:43 BindScope ~dtor 4
2018/12/06-20:36:43 out scope
2018/12/06-20:36:43 do print 4,         // output wrong
2018/12/06-20:36:43 do print 4,         // output wrong
2018/12/06-20:36:43 ending.........

, мы можем видеть, что когда bs был удален, ThreadPool задача lb_print работает неправильно (перебить неправильно).

0 голосов
/ 06 декабря 2018

Срок действия массива char не увеличивается, только указатель на него.

Вы следуете за висящим указателем и испытываете неопределенное поведение.

Если бы это был массив std, он был бы скопирован.

Неопределенное поведение может делать что угодно, в том числе «работать».

...