3
class Whatever
{
public:
    virtual ~Whatever();

protected:
    Whatever();
    virtual void SomeMethod();
    void OnEventOccurred(int x);

    std::vector<boost::signals2::scoped_connection> boostSignalConnections_;
}

// .cpp

Whatever::SomeMethod()
{
    ...
    boostSignalConnections_.push_back(
        anObject->AddEventOccurredObserver(
            std::bind(&Whatever::OnEventOccurred,
                      this, std::placeholders::_1)));
    ...
}

(Note AddEventOccurredObserver just delegates to boost::signals2::connect() and returns the boost::signals2::connection)

I'm getting the following error. It's hard to interpret template errors but it seems like the error is being caused at the member declaration of std::vector<boost::signals2::scoped_connection> boostSignalConnections_;

...\vc\include\xmemory(202): error C2248:  
    'boost::signals2::scoped_connection::scoped_connection' :
    cannot access private member declared in class 'boost::signals2::scoped_connection'
...\boost_1_47\boost\signals2\connection.hpp(234) : see declaration of
'boost::signals2::scoped_connection::scoped_connection'
...\boost_1_47\boost\signals2\connection.hpp(210) :
    see declaration of 'boost::signals2::scoped_connection'
...\vc\include\xmemory(201) : while compiling class template member function
'void std::allocator<_Ty>::construct(boost::signals2::scoped_connection *,_Ty &&)'
with
[
    _Ty=boost::signals2::scoped_connection
]

I've searched and I think it might have to do with scoped_connection not being copyable? I'm not sure. The reason I'm using a scoped_connection is because of this SO question: Handle connection/disconnection of many signals/slots with boost::signals2

Update

FYI, when I change from scoped_connection to connection it works: std::vector<boost::signals2::connection> boostSignalConnections_;. My whole reason for using scoped_connection is that they automatically disconnect the connection on destruction whereas I believe a connection doesn't not. However, I can just iterate over the collection and manually disconnect each one.

Community
  • 1
  • 1
User
  • 62,498
  • 72
  • 186
  • 247
  • You're correct that the problem is that the copy constructor is private. Since `vector` needs to copy the elements in the case of a reallocation (e.g. due to expansion), this is a problem. I don't have the best solution for you though, so I'll leave it to other to actually answer the implicit question of "what should I do instead?" My first, naive response would be to keep a vector of pointers/references to heap-allocated connections, but that obviously pretty much eliminates the usefulness of the `scoped` part of the equation. – tmpearce May 04 '12 at 02:12

1 Answers1

9

boost::signals2::scoped_connection is non-copyable, and in C++03, std::vector<T> requires that T be both copy-constructible and copy-assignable (this requirement is relaxed in C++11, where a non-copyable type is fine as long as it's movable instead).

The naive solution would be to make boostSignalConnections_ a std::vector<scoped_connection*> instead, but this introduces object lifetime and exception-safety issues that aren't worth the effort. Instead, depending on how recent your compiler is, I'd recommend the following:

  • C++03: Use boost::ptr_vector<scoped_connection>, which will store pointers for you (allowing non-copyable types) but give you value-semantics, and eliminate the aforementioned object lifetime and exception-safety issues.
  • C++11: The above is still a valid option, but the more idiomatic approach would be to use std::vector<std::unique_ptr<scoped_connection>>.

That being said, why used scoped_connection if you don't want your object to be lexically-scoped?

ildjarn
  • 62,044
  • 9
  • 127
  • 211
  • Good question, but as I mentioned I was following the example in the question linked to in my question (although that uses a map so maybe it's different?) It seemed unusual to me to use a scoped object in container but I'm not that familiar with them. – User May 04 '12 at 02:33
  • @User : Right, associative container values have weaker requirements than sequence container values and associative container keys. – ildjarn May 04 '12 at 02:39
  • @ildjarn When you say `boost::ptr_vector<>` maintains object lifetime, does it mean it is deploying smart_pointers at the backend to achieve the same? If so, which one? – CinCout Apr 24 '18 at 09:47
  • @CinCout : I haven't looked at the implementation but AFAIK that's a non-public implementation detail; likely it wouldn't be useful outside of the context of the library. Better to think of `boost::ptr_vector<>` as a "smart container" that obviates the need for a smart pointer. ;-] – ildjarn Apr 24 '18 at 12:19
  • @ildjarn So it is guaranteed that the memory management is handled by the container? Or are there any (extra)ordinary exceptions to the same? – CinCout Apr 24 '18 at 12:41
  • @CinCout : It's guaranteed – that's the entire reason for the library's existence, after all. TBH I'm not sure what your question is that isn't addressed on the front page of the library docs... – ildjarn Apr 24 '18 at 17:22