Is the new boost :: thread calling the object's destructor many times longer than expected?

The strange behavior of the code below causes the object's destructor to be called more than once. While the code doesn't crash, as a result, I just want to know why this behavior is happening. This is a very simple common program pattern that is probably used by many people around the Boost area, but I still haven't noticed this behavior.

#include <boost/thread.hpp>
#include <iostream>

class object
{
    private:

        int value;

    public:

    object();
    ~object();
    void pass( int value);
};

object::object()
{
    std::cout<<"constructing object: "<<this<<" with value: "<<this->object::value<<std::endl;
}
object::~object()
{
    std::cout<<"destructing  object: "<<this<<" with value: "<<this->object::value<<std::endl;
}
void object::pass( int value)
{
    this->object::value = value;
    std::cout<<"value passed is: "<<this->object::value<<std::endl;
}

class threaded
{
    private:

         object A;

    public:

    threaded();
    ~threaded();
    void init( int value);
};
threaded::threaded(){}
threaded::~threaded(){}
void threaded::init( int value)
{
    this->threaded::A.pass( value);
}

int main()
{
    threaded T;
    int unlucky_number = 13;

    boost::thread_group tg;

    tg.add_thread( new boost::thread( boost::bind( &threaded::init, T, unlucky_number)));

    tg.join_all();

    return 0;
}

      

Here's the output of the code.

constructing object: 0x7ffcb53157f0 with value: 0

destructing  object: 0x7ffcb53156d0 with value: 0 <----From here?
destructing  object: 0x7ffcb5315720 with value: 0
destructing  object: 0x7ffcb53157a0 with value: 0
destructing  object: 0x7ffcb5315780 with value: 0
destructing  object: 0x7ffcb5315710 with value: 0
destructing  object: 0x7ffcb53157c0 with value: 0
destructing  object: 0x7ffcb5315820 with value: 0
destructing  object: 0x7ffcb5315800 with value: 0 <----To here?

value passed is: 13
destructing  object: 0x1a5f2d8 with value: 13
destructing  object: 0x7ffcb53157f0 with value: 0

      

Objects destroyed after the first one built and before the string needs to be somehow created by the copy constructor inside the boost stream library, but why were they never built and why is there no crash? Plus their values ​​are always zero, so this is not garbage memory ... any ideas? value passed is: 13

Thus, at the request of G.M. I tried to create copy constructors just to get promotion related errors in the error_code.hpp file.

Here's the new code plus compilation errors.

#include <boost/thread.hpp>
#include <iostream>

class object
{
    private:

        int value;

    public:

    object();
    object( object const &copy_this);
    ~object();
    void pass( int value);
};

object::object()
{
    std::cout<<"constructing object: "<<this<<" with value: "<<this->object::value<<std::endl;
}
object::object( object const &copy_this)
{
    std::cout<<"object copy constructor. "<<std::endl;
    this->object::value = copy_this.value;
}
object::~object()
{
    std::cout<<"destructing  object: "<<this<<" with value: "<<this->object::value<<std::endl;
}
void object::pass( int value)
{
    this->object::value = value;
    std::cout<<"value passed is: "<<this->object::value<<std::endl;
}

class threaded
{
    private:

         object A;

    public:

    threaded();
    threaded( threaded const &copy_this);
    ~threaded();
    void init( int value);
};
threaded::threaded(){}
threaded::threaded( threaded const &copy_this)
{
    std::cout<<"threaded copy constructor. "<<std::endl;
    this->threaded::A = copy_this.A;
}
threaded::~threaded(){}
void threaded::init( int value)
{
    this->threaded::A.pass( value);
}

int main()
{
    threaded T;
    int unlucky_number = 13;

    boost::thread_group tg;

    tg.add_thread( new boost::thread( boost::bind( &threaded::init, T, unlucky_number)));

    tg.join_all();
    //T.init(13);

    return 0;
}

||=== Build: Debug in boost_thread_destructor_problem (compiler: GNU GCC Compiler) ===|
obj/Debug/boost_thread_destructor_problem.o||In function `__static_initialization_and_destruction_0(int, int)':|
/usr/include/boost/system/error_code.hpp|221|undefined reference to `boost::system::generic_category()'|
/usr/include/boost/system/error_code.hpp|222|undefined reference to `boost::system::generic_category()'|
/usr/include/boost/system/error_code.hpp|223|undefined reference to `boost::system::system_category()'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::thread_exception::thread_exception(int, char const*)':|
/usr/include/boost/thread/exceptions.hpp|51|undefined reference to `boost::system::system_category()'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::condition_error::condition_error(int, char const*)':|
/usr/include/boost/thread/exceptions.hpp|84|undefined reference to `boost::system::system_category()'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::detail::thread_data_base::thread_data_base()':|
/usr/include/boost/thread/pthread/thread_data.hpp|152|undefined reference to `vtable for boost::detail::thread_data_base'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::detail::interruption_checker::interruption_checker(pthread_mutex_t*, pthread_cond_t*)':|
/usr/include/boost/thread/pthread/thread_data.hpp|195|undefined reference to `boost::detail::get_current_thread_data()'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::thread::start_thread()':|
/usr/include/boost/thread/detail/thread.hpp|179|undefined reference to `boost::thread::start_thread_noexcept()'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::thread::~thread()':|
/usr/include/boost/thread/detail/thread.hpp|254|undefined reference to `boost::thread::detach()'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::thread::get_id() const':|
/usr/include/boost/thread/detail/thread.hpp|741|undefined reference to `boost::thread::native_handle()'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::thread::join()':|
/usr/include/boost/thread/detail/thread.hpp|767|undefined reference to `boost::thread::join_noexcept()'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::condition_variable::wait(boost::unique_lock<boost::mutex>&)':|
/usr/include/boost/thread/pthread/condition_variable.hpp|84|undefined reference to `boost::this_thread::interruption_point()'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::shared_mutex::lock_shared()':|
/usr/include/boost/thread/pthread/shared_mutex.hpp|186|undefined reference to `boost::this_thread::disable_interruption::disable_interruption()'|
/usr/include/boost/thread/pthread/shared_mutex.hpp|186|undefined reference to `boost::this_thread::disable_interruption::~disable_interruption()'|
/usr/include/boost/thread/pthread/shared_mutex.hpp|186|undefined reference to `boost::this_thread::disable_interruption::~disable_interruption()'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::shared_mutex::lock()':|
/usr/include/boost/thread/pthread/shared_mutex.hpp|287|undefined reference to `boost::this_thread::disable_interruption::disable_interruption()'|
/usr/include/boost/thread/pthread/shared_mutex.hpp|287|undefined reference to `boost::this_thread::disable_interruption::~disable_interruption()'|
/usr/include/boost/thread/pthread/shared_mutex.hpp|287|undefined reference to `boost::this_thread::disable_interruption::~disable_interruption()'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::thread_group::join_all()':|
/usr/include/boost/thread/detail/thread_group.hpp|117|undefined reference to `boost::thread::joinable() const'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::detail::thread_data<boost::_bi::bind_t<void, boost::_mfi::mf1<void, threaded, int>, boost::_bi::list2<boost::_bi::value<threaded>, boost::_bi::value<int> > > >::thread_data(boost::_bi::bind_t<void, boost::_mfi::mf1<void, threaded, int>, boost::_bi::list2<boost::_bi::value<threaded>, boost::_bi::value<int> > >)':|
/usr/include/boost/thread/detail/thread.hpp|109|undefined reference to `boost::detail::thread_data_base::~thread_data_base()'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::detail::thread_data<boost::_bi::bind_t<void, boost::_mfi::mf1<void, threaded, int>, boost::_bi::list2<boost::_bi::value<threaded>, boost::_bi::value<int> > > >::~thread_data()':|
/usr/include/boost/thread/detail/thread.hpp|90|undefined reference to `boost::detail::thread_data_base::~thread_data_base()'|
/usr/include/boost/thread/detail/thread.hpp|90|undefined reference to `boost::detail::thread_data_base::~thread_data_base()'|
obj/Debug/boost_thread_destructor_problem.o:(.rodata._ZTIN5boost6detail11thread_dataINS_3_bi6bind_tIvNS_4_mfi3mf1Iv8threadediEENS2_5list2INS2_5valueIS6_EENS9_IiEEEEEEEE[_ZTIN5boost6detail11thread_dataINS_3_bi6bind_tIvNS_4_mfi3mf1Iv8threadediEENS2_5list2INS2_5valueIS6_EENS9_IiEEEEEEEE]+0x10)||undefined reference to `typeinfo for boost::detail::thread_data_base'|
||error: ld returned 1 exit status|
||=== Build failed: 24 error(s), 0 warning(s) (0 minute(s), 2 second(s)) ===|

      

+3


source to share


2 answers


Due to the way you called boost::bind

...

tg.add_thread(new boost::thread(boost::bind(&threaded::init, T, unlucky_number)));

      

T

will be passed by value. This can lead to arbitrary copying T

done by the implementation boost::bind

.

Since you know what the T

thread on which it is being used will experience in this case, you can either force follow the link ...



tg.add_thread(new boost::thread(boost::bind(&threaded::init, boost::ref(T), unlucky_number)));

      

or pass a pointer ...

tg.add_thread(new boost::thread(boost::bind(&threaded::init, &T, unlucky_number)));

      

+2


source


You can alleviate most of this by avoiding bind

. Lambdas solves this problem - most often more efficiently:

C ++ 11

tg.create_thread([=]() mutable { T.init(unlucky_number); });

      

In C ++ 14, you might be a little more advanced :



tg.create_thread([T=std::move(T), unlucky_number = 13]() mutable { T.init(unlucky_number); });

      

If it's object

expensive to copy, consider making it moveable, for example.

object(object const&)       = default;
object(object&&)            = default;
object& operator=(object&&) = default;

      

To make the compiler generate special elements even if you added user-declared (non-trivial) constructor / destructor elements.

+3


source







All Articles