PPI: Remove disconnected connectors from MultiConnectorMixin modules
g0dil [Fri, 23 Oct 2009 15:47:22 +0000 (15:47 +0000)]
git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@1506 270642c3-0616-0410-b53a-bc976706d245

12 files changed:
senf/PPI/AnnotationRouter.hh
senf/PPI/AnnotationRouter.test.cc
senf/PPI/Connectors.cc
senf/PPI/Connectors.cci
senf/PPI/Connectors.hh
senf/PPI/Joins.test.cc
senf/PPI/MultiConnectorMixin.ct [new file with mode: 0644]
senf/PPI/MultiConnectorMixin.cti
senf/PPI/MultiConnectorMixin.hh
senf/PPI/MultiConnectorMixin.ih
senf/PPI/MultiConnectorMixin.mpp
senf/PPI/MultiConnectorMixin.test.cc

index d52f58a..6f4300c 100644 (file)
@@ -104,7 +104,7 @@ namespace module {
     public:
         connector::PassiveInput<> input;
         connector::ActiveOutput<> defaultOutput;
-        
+
         AnnotationRouter();
 
         struct DuplicateKeyException : public senf::Exception
index e832403..25fac4c 100644 (file)
@@ -49,6 +49,11 @@ namespace {
 
     std::ostream & operator<<(std::ostream & os, IntAnnotation const & value)
     { os << value.value; return os; }
+
+    struct AnnotationRouter : public senf::ppi::module::AnnotationRouter<IntAnnotation>
+    {
+        using senf::ppi::module::AnnotationRouter<IntAnnotation>::connectors;
+    };
 }
 
 BOOST_AUTO_UNIT_TEST(annotationRouter)
@@ -57,7 +62,7 @@ BOOST_AUTO_UNIT_TEST(annotationRouter)
     senf::ppi::module::debug::PassiveSink sink1;
     senf::ppi::module::debug::PassiveSink sink2;
 
-    senf::ppi::module::AnnotationRouter<IntAnnotation> router;
+    AnnotationRouter router;
     
     senf::ppi::connect(source, router);
     senf::ppi::connect(router, 1, sink1);
@@ -81,6 +86,9 @@ BOOST_AUTO_UNIT_TEST(annotationRouter)
     BOOST_CHECK_EQUAL( sink2.size(), 1u );
     BOOST_CHECK( sink1.front() == p1 );
     BOOST_CHECK( sink2.front() == p2 );
+
+    BOOST_CHECK_EQUAL(router.connectors().size(), 2u);
+    sink1.input.disconnect();
 }
 
 ///////////////////////////////cc.e////////////////////////////////////////
index 156a717..debe7ec 100644 (file)
@@ -165,6 +165,7 @@ prefix_ void senf::ppi::connector::Connector::disconnect()
     // Cannot disconnected a non-connected connector
     SENF_ASSERT( peer_ &&
                  "senf::ppi::connector::Connector::disconnect(): Not connected" );
+
     Connector & peer (*peer_);
     peer_ = 0;
     peer.peer_ = 0;
@@ -173,6 +174,9 @@ prefix_ void senf::ppi::connector::Connector::disconnect()
         enqueueInitializable();
     if (! peer.initializationScheduled())
         peer.enqueueInitializable();
+
+    v_disconnected();
+    peer.v_disconnected();
 }
 
 prefix_ std::type_info const & senf::ppi::connector::Connector::packetTypeID()
@@ -180,6 +184,10 @@ prefix_ std::type_info const & senf::ppi::connector::Connector::packetTypeID()
     return typeid(void);
 }
 
+prefix_ void senf::ppi::connector::Connector::v_disconnected()
+    const
+{}
+
 ///////////////////////////////////////////////////////////////////////////
 // senf::ppi::connector::PassiveConnector
 
index f133b97..2abd3b1 100644 (file)
@@ -72,7 +72,9 @@ prefix_ senf::ppi::connector::Connector::~Connector()
     if (connected()) {
         Connector & peer (*peer_);
         peer_->peer_ = 0;
-        peer.v_init();
+        if (! peer.initializationScheduled())
+            peer.enqueueInitializable();
+        peer.v_disconnected();
     }
 }
 
index ddf907e..c0b0b49 100644 (file)
@@ -187,6 +187,8 @@ namespace connector {
         
     private:
         virtual std::type_info const & packetTypeID();
+        
+        virtual void v_disconnected() const;
 
         void setModule(module::Module & module);
 
index 433e2cb..d84a98a 100644 (file)
@@ -43,11 +43,20 @@ namespace connector = ppi::connector;
 namespace module = ppi::module;
 namespace debug = module::debug;
 
+namespace {
+
+    struct PassiveJoin : public module::PassiveJoin
+    {
+        using module::PassiveJoin::connectors;
+    };
+
+}
+
 BOOST_AUTO_UNIT_TEST(passiveJoin)
 {
     debug::ActiveSource source1;
     debug::ActiveSource source2;
-    module::PassiveJoin join;
+    PassiveJoin join;
     debug::PassiveSink sink;
 
     ppi::connect(source1, join);
@@ -71,6 +80,10 @@ BOOST_AUTO_UNIT_TEST(passiveJoin)
     BOOST_CHECK_EQUAL( sink.size(), 2u );
     sink.input.unthrottle();
     BOOST_CHECK_EQUAL( sink.size(), 4u );
+
+    BOOST_CHECK_EQUAL( join.connectors().size(), 2u);
+    source1.output.disconnect();
+    BOOST_CHECK_EQUAL( join.connectors().size(), 1u);
 }
 
 BOOST_AUTO_UNIT_TEST(priorityJoin)
diff --git a/senf/PPI/MultiConnectorMixin.ct b/senf/PPI/MultiConnectorMixin.ct
new file mode 100644 (file)
index 0000000..78ae255
--- /dev/null
@@ -0,0 +1,78 @@
+// $Id$
+//
+// Copyright (C) 2009 
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief MultiConnectorMixin non-inline template implementation  */
+
+#include "MultiConnectorMixin.ih"
+
+// Custom includes
+
+#include <boost/lambda/lambda.hpp>
+
+#define prefix_
+///////////////////////////////ct.p////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,KeyType_,ContainerType_>
+
+template <class Self_, class ConnectorType_, class KeyType_, class ContainerType_>
+prefix_ void
+senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,KeyType_,ContainerType_>::
+disconnected(ConnectorType_ const & c)
+{
+    typename ContainerType::iterator i (
+        find_if(connectors_.begin(), connectors_.end(),
+                boost::bind(&ContainerType_::value_type::second,_1) == &c));
+    if (i != connectors_.end())
+        connectors_.erase(i);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,void,ContainerType_>
+
+template <class Self_, class ConnectorType_, class ContainerType_>
+prefix_ void
+senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,void,ContainerType_>::
+disconnected(ConnectorType_ const & c)
+{
+    using boost::lambda::_1;
+
+    typename ContainerType::iterator i (
+        find_if(connectors_.begin(), connectors_.end(), &_1 == &c));
+    if (i != connectors_.end())
+        connectors_.erase(i);
+}
+
+///////////////////////////////ct.e////////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
index 3df16d8..fdaa92a 100644 (file)
 /** \file
     \brief MultiConnectorMixin inline template implementation */
 
-//#include "MultiConnectorMixin.ih"
+#include "MultiConnectorMixin.ih"
 
 // Custom includes
 
 #define prefix_ inline
 ///////////////////////////////cti.p///////////////////////////////////////
 
+///////////////////////////////////////////////////////////////////////////
+// senf::ppi::module::detail::MultiConnectorWrapper<Module,Connector>
+
+template <class Module, class Connector>
+prefix_ void senf::ppi::module::detail::MultiConnectorWrapper<Module, Connector>::v_disconnected()
+    const
+{
+    static_cast<Module&>(this->module()).disconnected(*this);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,KeyType_,ContainerType_>
+
 template <class Self_, class ConnectorType_, class KeyType_, class ContainerType_>
 prefix_ ContainerType_ &
 senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,KeyType_,ContainerType_>::connectors()
@@ -46,6 +59,15 @@ connectors()
     return connectors_;
 }
 
+template <class Self_, class ConnectorType_, class KeyType_, class ContainerType_>
+prefix_ void
+senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,KeyType_,ContainerType_>::
+connectorDestroy(ConnectorType const &)
+{}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,void,ContainerType_>
+
 template <class Self_, class ConnectorType_, class ContainerType_>
 prefix_ ContainerType_ &
 senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,void,ContainerType_>::connectors()
@@ -53,54 +75,34 @@ senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,void,ContainerType_>
     return connectors_;
 }
 
-#ifdef DOXYGEN
-
-// Only for exposition
-// Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
-
-template <class Self_, class ConnectorType_, class KeyType_, class ContainerType_>
-template <class A1>
-prefix_ ConnectorType_ &
-senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,KeyType_,ContainerType_>::
-newConnector(A1 const & a1)
+template <class Self_, class ConnectorType_, class ContainerType_>
+prefix_ ContainerType_ const &
+senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,void,ContainerType_>::connectors()
+    const
 {
-    std::auto_ptr<ConnectorType_> conn (new ConnectorType_);
-    KeyType_ key (static_cast<Self_*>(this)->connectorSetup(*conn, a1));
-    return * connectors_.insert(key, conn).first->second;
+    return connectors_;
 }
 
 template <class Self_, class ConnectorType_, class ContainerType_>
-template <class A1>
-prefix_ ConnectorType_ &
+prefix_ void
 senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,void,ContainerType_>::
-newConnector(A1 const & a1)
-{
-    connectors_.push_back(new ConnectorType_);
-    ConnectorType_ & conn (connectors_.back());
-    try { static_cast<Self_*>(this)->connectorSetup(conn , a1); }
-    catch (...) { connectors_.pop_back(); throw; }
-    return conn;
-}
+connectorDestroy(ConnectorType const &)
+{}
 
-template <class Source, class Target , class A1>
-typename boost::enable_if<
-    boost::is_base_of<senf::ppi::connector::OutputConnector, typename Source::ConnectorType>,
-    typename Source::ConnectorType & >::type
-senf::ppi::connect(Source & source, Target & target , A1 const & a1)
-{
-    connect(source.newConnector(a1), target);
-}
+///////////////////////////////////////////////////////////////////////////
+// senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,void,void>
 
-template <class Source, class Target , class A1>
-typename boost::enable_if<
-    boost::is_base_of<senf::ppi::connector::InputConnector, typename Target::ConnectorType>,
-    typename Target::ConnectorType & >::type
-senf::ppi::connect(Source & source, Target & target , A1 const & a1)
+template <class Self_, class ConnectorType_>
+prefix_ void
+senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,void,void>::
+disconnected(ConnectorType_ const & c)
 {
-    connect(source, target.newConnector(a1));
+    static_cast<Self_*>(this)->connectorDestroy(&c);
 }
 
-#else
+////////////////////////////////////////////////////////////////////////
+
+#ifndef DOXYGEN
 
 // Include 'Implementation' from MultiConnectorMixin.mpp
 #define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
index 1619eca..e9b42b0 100644 (file)
@@ -116,6 +116,12 @@ namespace module {
                 route(input, output);
                 input.onThrottle(&MyModule::doThrottle);
             }
+        
+            // Optional
+            void connectorDestroy(senf::ppi::connector::ActiveInput const & input)
+            {
+                 //  whatever
+            }
 
             void doThrottle()
             { 
@@ -131,6 +137,7 @@ namespace module {
         \li inheriting from MultiConnectorMixin
         \li defining a function \c connectorSetup
         \li declaring the mixin as a friend
+        \li optionally defining \c connectorDestroy to be notified when connectors are disconnected
 
         The MultiConnectorMixin takes several template arguments
         \li the name of the derived class, \a Self_
@@ -148,10 +155,8 @@ namespace module {
         \code
         container().insert(begin(), container().pop_back().release());
         \endcode
-        which will move the new connector from the end to the beginning. 
-        \warning If you throw an exception from \c connectorSetup(), you must do so \e before moving
-            the new connector around since the mixin will remove the last element from the container
-            on an exception.
+        which will move the new connector from the end to the beginning. If you want to abort adding
+        the new connector, you may throw an exception.
 
         \par "Example:" senf::ppi::module::PriorityJoin
 
@@ -163,7 +168,7 @@ namespace module {
         will this be written to the container only \e after \c connectorSetup() returns.
 
         When the returned key is not unique, the new connector will \e replace the old one. If this
-        is not, what you want, either check for an already existing member and throw an exception in
+        is not what you want, either check for an already existing member and throw an exception in
         \c connectorSetup() or replace the \c boost::ptr_map by a \c boost::ptr_multimap using the
         fourth template argument to MultiConnectorMixin.
 
@@ -204,7 +209,10 @@ namespace module {
         If you need to use a completely different type of container, you can take over the container
         management yourself. To do this, pass \c void as container type and change \c
         connectorSetup() to take an \c std::auto_ptr as argument. \c connectorSetup() must ensure to
-        save this connector in some container or throw an exception
+        save this connector in some container or throw an exception.
+
+        Implementing \c connectorDestroy now is \e mandatory. The signature is changed to take a
+        pointer as argument
         \code
         class MyModule 
             : public senf::ppi::module::Module,
@@ -224,6 +232,15 @@ namespace module {
                 connectors_.insert(connectors_.begin()+p,conn);
             }
 
+            void connectorDestroy(ConnectorType const * conn)
+            {
+                using boost::lambda::_1;
+                boost::ptr_vector<ConnectorType>::iterator i (
+                    std::find_if(connectors_.begin(),connectors_.end(), &_1==conn))
+                if (i != connectors_.end())
+                    connectors_.erase(i);
+            }
+
             boost::ptr_vector<ConnectorType> connectors_;
         };
         \endcode
@@ -245,18 +262,14 @@ namespace module {
 
     protected:
         typedef ContainerType_ ContainerType; ///< Type of connector container
+
         ContainerType_ & connectors();        ///< Get connector container
         ContainerType_ const & connectors() const; ///< Get connectors container (const)
 
-    private:
-#if 0
-        // For exposition only
-        // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
+        void connectorDestroy(ConnectorType const &);
 
-        tempalte <class A1>
-        ConnectorType_ & newConnector(A1 const & a1);
+    private:
 
-#endif
 #ifndef DOXYGEN
 
         // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
@@ -269,7 +282,10 @@ namespace module {
 
 #endif
 
+        void disconnected(ConnectorType_ const & c);
+
         friend class detail::MultiConnectorMixinAccess;
+        friend class detail::MultiConnectorWrapper<Self_,ConnectorType_>;
         
         ContainerType_ connectors_;
     };
@@ -287,30 +303,13 @@ namespace module {
         
     protected:
         typedef ContainerType_ ContainerType;
-        ContainerType_ & connectors();
 
-    private:
-
-#if 0
-        // For exposition only
-        // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
+        ContainerType_ & connectors();
+        ContainerType_ const & connectors() const;
 
-        tempalte <class A1>
-        ConnectorType_ & newConnector(A1 const & a1);
+        void connectorDestroy(ConnectorType const &);
 
-        // See above for an additional note regarding the boost::enable_if in the real
-        // implementation
-        
-        template <class Source, class Target, class A1>
-        friend Source::ConnectorType & senf::ppi::connect(Source & source, 
-                                                          Target & target, 
-                                                          A1 const & a1);
-
-        template <class Source, class Target, class A1>
-        friend Target::ConnectorType & senf::ppi::connect(Source & source,
-                                                          Target & target,
-                                                          A1 const & a1);
-#endif
+    private:
 
         // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
 #       define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
@@ -319,15 +318,11 @@ namespace module {
             SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
             1 ))
 #       include BOOST_PP_ITERATE()
-        
-#       define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
-            0, \
-            2*SENF_MULTI_CONNECTOR_MAX_ARGS, \
-            SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
-            9 ))
-#       include BOOST_PP_ITERATE()
 
+        void disconnected(ConnectorType_ const & c);
+        
         friend class detail::MultiConnectorMixinAccess;
+        friend class detail::MultiConnectorWrapper<Self_,ConnectorType_>;
 
         ContainerType_ connectors_;
     };
@@ -342,27 +337,6 @@ namespace module {
 
     private:
 
-#if 0
-        // For exposition only
-        // Other implementations with 0..SENF_MULTI_CONNECTOR_MAX_ARGS arguments accordingly
-
-        tempalte <class A1>
-        ConnectorType_ & newConnector(A1 const & a1);
-
-        // See above for an additional note regarding the boost::enable_if in the real
-        // implementation
-        
-        template <class Source, class Target, class A1>
-        friend Source::ConnectorType & senf::ppi::connect(Source & source, 
-                                                          Target & target, 
-                                                          A1 const & a1);
-
-        template <class Source, class Target, class A1>
-        friend Target::ConnectorType & senf::ppi::connect(Source & source,
-                                                          Target & target,
-                                                          A1 const & a1);
-#endif
-
         // Include 'MultiConnectorMixin member declaration' from MultiConnectorMixin.mpp
 #       define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
             0, \
@@ -371,14 +345,10 @@ namespace module {
             1 ))
 #       include BOOST_PP_ITERATE()
 
-#       define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
-            0, \
-            2*SENF_MULTI_CONNECTOR_MAX_ARGS, \
-            SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
-            9 ))
-#       include BOOST_PP_ITERATE()
+        void disconnected(ConnectorType_ const & c);
 
         friend class detail::MultiConnectorMixinAccess;
+        friend class detail::MultiConnectorWrapper<Self_,ConnectorType_>;
     };
 
 #endif
@@ -387,7 +357,7 @@ namespace module {
 
 ///////////////////////////////hh.e////////////////////////////////////////
 //#include "MultiConnectorMixin.cci"
-//#include "MultiConnectorMixin.ct"
+#include "MultiConnectorMixin.ct"
 #include "MultiConnectorMixin.cti"
 #endif
 
index 5207def..e6f3d1c 100644 (file)
@@ -51,6 +51,14 @@ namespace detail {
         typedef boost::ptr_map<KeyType, ConnectorType> type; 
     };
 
+    template <class Module, class Connector>
+    class MultiConnectorWrapper
+        : public Connector
+    {
+    private:
+        virtual void v_disconnected() const;
+    };
+
 #ifndef DOXYGEN
 
     template <class ConnectorType>
index 0bfeda7..8000c67 100644 (file)
@@ -157,7 +157,7 @@ prefix_ ConnectorType_ &
 senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,KeyType_,ContainerType_>::
 newConnector(mpp_FnParams())
 {
-    std::auto_ptr<ConnectorType_> conn (new ConnectorType_);
+    std::auto_ptr<ConnectorType_> conn (new detail::MultiConnectorWrapper<Self_,ConnectorType_>);
     KeyType_ key (static_cast<Self_*>(this)->connectorSetup(*conn mpp_CallParamsKomma()));
     return * connectors_.insert(key, conn).first->second;
 }
@@ -171,10 +171,10 @@ prefix_ ConnectorType_ &
 senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,void,ContainerType_>::
 newConnector(mpp_FnParams())
 {
-    connectors_.push_back(new ConnectorType_);
+    connectors_.push_back(new detail::MultiConnectorWrapper<Self_,ConnectorType_>);
     ConnectorType_ & conn (connectors_.back());
     try { static_cast<Self_*>(this)->connectorSetup(conn mpp_CallParamsKomma()); }
-    catch (...) { connectors_.pop_back(); throw; }
+    catch (...) { disconnected(conn); throw; }
     return conn;
 }
 
@@ -187,7 +187,7 @@ prefix_ ConnectorType_ &
 senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,void,void>::
 newConnector(mpp_FnParams())
 {
-    std::auto_ptr<ConnectorType_> cp (new ConnectorType_);
+    std::auto_ptr<ConnectorType_> cp (new detail::MultiConnectorWrapper<Self_,ConnectorType_>);
     ConnectorType_ & cref (*cp);
     static_cast<Self_*>(this)->connectorSetup(cp mpp_CallParamsKomma());
     return cref;
index 84fcbaf..498ce00 100644 (file)
@@ -50,6 +50,7 @@ namespace {
           public module::MultiConnectorMixin<MyModule, connector::ActiveOutput<>, void, void>
     {
         SENF_PPI_MODULE(MyModule);
+        typedef std::vector< boost::shared_ptr<MyModule::ConnectorType> > Connectors;
     public:
         connector::PassiveInput<> input;
 
@@ -59,6 +60,9 @@ namespace {
             input.onRequest(&MyModule::request);
         }
 
+        Connectors const & connectors() const
+        { return connectors_; }
+
     private:
         void connectorSetup(std::auto_ptr<ConnectorType> c)
         {
@@ -66,6 +70,15 @@ namespace {
             connectors_.push_back(boost::shared_ptr<ConnectorType>(c));
         }
 
+        void connectorDestroy(ConnectorType const * c)
+        {
+            Connectors::iterator i (
+                std::find_if(connectors_.begin(), connectors_.end(), 
+                             boost::bind(&Connectors::value_type::get,_1) == c));
+            if (i != connectors_.end())
+                connectors_.erase(i);
+        }
+
         void request()
         {
             senf::Packet p (input());
@@ -74,7 +87,6 @@ namespace {
                 (**i)(p);
         }
 
-        typedef std::vector< boost::shared_ptr<MyModule::ConnectorType> > Connectors;
         Connectors connectors_;
                 
         friend class module::MultiConnectorMixin<MyModule, connector::ActiveOutput<>, void, void>;
@@ -110,6 +122,10 @@ BOOST_AUTO_UNIT_TEST(multiConnectorMixin_userContainer)
     BOOST_CHECK_EQUAL( sink2.size(), 1u );
     BOOST_CHECK( sink1.pop_front() == p );
     BOOST_CHECK( sink2.pop_front() == p );
+
+    BOOST_CHECK_EQUAL( module.connectors().size(), 2u );
+    sink1.input.disconnect();
+    BOOST_CHECK_EQUAL( module.connectors().size(), 1u );
 }
 
 BOOST_AUTO_UNIT_TEST(multiConnectorMixin_multipleModules)