"Fossies" - the Fresh Open Source Software Archive

Member "libsigc++-2.10.2/tests/test_bind_refptr.cc" (5 May 2019, 13590 Bytes) of package /linux/misc/libsigc++-2.10.2.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 // Bug 564005 - Valgrind errors and crash on exit with Gtk::UIManager
    2 // Bug 154498 - Unnecessary warning on console: signalproxy_connectionnode.cc
    3 
    4 // libsigc++-only test case. (Or almost so. RefPtr is stolen from glibmm.)
    5 
    6 // This test case is much more useful if it's run under valgrind.
    7 
    8 #include "testutilities.h"
    9 #include <sigc++/sigc++.h>
   10 #include <sstream>
   11 #include <cstdlib>
   12 
   13 #define ACTIVATE_BUG 1
   14 
   15 // -*- c++ -*-
   16 #ifndef _GLIBMM_REFPTR_H
   17 #define _GLIBMM_REFPTR_H
   18 
   19 /* Copyright 2002 The gtkmm Development Team
   20  *
   21  * This library is free software; you can redistribute it and/or
   22  * modify it under the terms of the GNU Lesser General Public
   23  * License as published by the Free Software Foundation; either
   24  * version 2.1 of the License, or (at your option) any later version.
   25  *
   26  * This library is distributed in the hope that it will be useful,
   27  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   29  * Lesser General Public License for more details.
   30  *
   31  * You should have received a copy of the GNU Lesser General Public
   32  * License along with this library; if not, write to the Free
   33  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   34  */
   35 
   36 //#include <glibmmconfig.h>
   37 
   38 namespace Glib
   39 {
   40 
   41 /** RefPtr<> is a reference-counting shared smartpointer.
   42  *
   43  * Some objects in gtkmm are obtained from a shared
   44  * store. Consequently you cannot instantiate them yourself. Instead they
   45  * return a RefPtr which behaves much like an ordinary pointer in that members
   46  * can be reached with the usual <code>object_ptr->member</code> notation.
   47  * Unlike most other smart pointers, RefPtr doesn't support dereferencing
   48  * through <code>*object_ptr</code>.
   49  *
   50  * Reference counting means that a shared reference count is incremented each
   51  * time a RefPtr is copied, and decremented each time a RefPtr is destroyed,
   52  * for instance when it leaves its scope. When the reference count reaches
   53  * zero, the contained object is deleted, meaning  you don't need to remember
   54  * to delete the object.
   55  *
   56  * RefPtr<> can store any class that has reference() and unreference() methods.
   57  * In gtkmm, that is anything derived from Glib::ObjectBase, such as
   58  * Gdk::Pixmap.
   59  *
   60  * See the "Memory Management" section in the "Programming with gtkmm"
   61  * book for further information.
   62  */
   63 template <class T_CppObject>
   64 class RefPtr
   65 {
   66 public:
   67   /** Default constructor
   68    *
   69    * Afterwards it will be null and use of -> will cause a segmentation fault.
   70    */
   71   inline RefPtr();
   72 
   73   /// Destructor - decrements reference count.
   74   inline ~RefPtr();
   75 
   76   /// For use only by the ::create() methods.
   77   explicit inline RefPtr(T_CppObject* pCppObject);
   78 
   79   /** Copy constructor
   80    *
   81    * This increments the shared reference count.
   82    */
   83   inline RefPtr(const RefPtr<T_CppObject>& src);
   84 
   85   /** Copy constructor (from different, but castable type).
   86    *
   87    * Increments the reference count.
   88    */
   89   template <class T_CastFrom>
   90   inline RefPtr(const RefPtr<T_CastFrom>& src);
   91 
   92   /** Swap the contents of two RefPtr<>.
   93    * This method swaps the internal pointers to T_CppObject.  This can be
   94    * done safely without involving a reference/unreference cycle and is
   95    * therefore highly efficient.
   96    */
   97   inline void swap(RefPtr<T_CppObject>& other);
   98 
   99   /// Copy from another RefPtr:
  100   inline RefPtr<T_CppObject>& operator=(const RefPtr<T_CppObject>& src);
  101 
  102   /** Copy from different, but castable type).
  103    *
  104    * Increments the reference count.
  105    */
  106   template <class T_CastFrom>
  107   inline RefPtr<T_CppObject>& operator=(const RefPtr<T_CastFrom>& src);
  108 
  109   /// Tests whether the RefPtr<> point to the same underlying instance.
  110   inline bool operator==(const RefPtr<T_CppObject>& src) const;
  111 
  112   /// See operator==().
  113   inline bool operator!=(const RefPtr<T_CppObject>& src) const;
  114 
  115   /** Dereferencing.
  116    *
  117    * Use the methods of the underlying instance like so:
  118    * <code>refptr->memberfun()</code>.
  119    */
  120   inline T_CppObject* operator->() const;
  121 
  122   /** Test whether the RefPtr<> points to any underlying instance.
  123    *
  124    * Mimics usage of ordinary pointers:
  125    * @code
  126    *   if (ptr)
  127    *     do_something();
  128    * @endcode
  129    */
  130   inline explicit operator bool() const;
  131 
  132 #ifndef GLIBMM_DISABLE_DEPRECATED
  133   /// @deprecated Use reset() instead because this leads to confusion with clear() methods on the underlying class. For instance, people use .clear() when they mean ->clear().
  134   inline void clear();
  135 #endif //GLIBMM_DISABLE_DEPRECATED
  136 
  137   /** Set underlying instance to 0, decrementing reference count of existing instance appropriately.
  138    * @newin{2,16}
  139    */
  140   inline void reset();
  141 
  142   /** Dynamic cast to derived class.
  143    *
  144    * The RefPtr can't be cast with the usual notation so instead you can use
  145    * @code
  146    *   ptr_derived = RefPtr<Derived>::cast_dynamic(ptr_base);
  147    * @endcode
  148    */
  149   template <class T_CastFrom>
  150   static inline RefPtr<T_CppObject> cast_dynamic(const RefPtr<T_CastFrom>& src);
  151 
  152   /** Static cast to derived class.
  153    *
  154    * Like the dynamic cast; the notation is
  155    * @code
  156    *   ptr_derived = RefPtr<Derived>::cast_static(ptr_base);
  157    * @endcode
  158    */
  159   template <class T_CastFrom>
  160   static inline RefPtr<T_CppObject> cast_static(const RefPtr<T_CastFrom>& src);
  161 
  162   /** Cast to non-const.
  163    *
  164    * The RefPtr can't be cast with the usual notation so instead you can use
  165    * @code
  166    *   ptr_unconst = RefPtr<UnConstType>::cast_const(ptr_const);
  167    * @endcode
  168    */
  169   template <class T_CastFrom>
  170   static inline RefPtr<T_CppObject> cast_const(const RefPtr<T_CastFrom>& src);
  171 
  172   /** Compare based on the underlying instance address.
  173    *
  174    * This is needed in code that requires an ordering on
  175    * RefPtr<T_CppObject> instances, e.g. std::set<RefPtr<T_CppObject> >.
  176    *
  177    * Without these, comparing two RefPtr<T_CppObject> instances
  178    * is still syntactically possible, but the result is semantically
  179    * wrong, as p1 REL_OP p2 is interpreted as (bool)p1 REL_OP (bool)p2.
  180    */
  181   inline bool operator<(const RefPtr<T_CppObject>& src) const;
  182 
  183   /// See operator<().
  184   inline bool operator<=(const RefPtr<T_CppObject>& src) const;
  185 
  186   /// See operator<().
  187   inline bool operator>(const RefPtr<T_CppObject>& src) const;
  188 
  189   /// See operator<().
  190   inline bool operator>=(const RefPtr<T_CppObject>& src) const;
  191 
  192 private:
  193   T_CppObject* pCppObject_;
  194 };
  195 
  196 
  197 #ifndef DOXYGEN_SHOULD_SKIP_THIS
  198 
  199 // RefPtr<>::operator->() comes first here since it's used by other methods.
  200 // If it would come after them it wouldn't be inlined.
  201 
  202 template <class T_CppObject> inline
  203 T_CppObject* RefPtr<T_CppObject>::operator->() const
  204 {
  205   return pCppObject_;
  206 }
  207 
  208 template <class T_CppObject> inline
  209 RefPtr<T_CppObject>::RefPtr()
  210 :
  211   pCppObject_ (nullptr)
  212 {}
  213 
  214 template <class T_CppObject> inline
  215 RefPtr<T_CppObject>::~RefPtr()
  216 {
  217   if(pCppObject_)
  218     pCppObject_->unreference(); // This could cause pCppObject to be deleted.
  219 }
  220 
  221 template <class T_CppObject> inline
  222 RefPtr<T_CppObject>::RefPtr(T_CppObject* pCppObject)
  223 :
  224   pCppObject_ (pCppObject)
  225 {}
  226 
  227 template <class T_CppObject> inline
  228 RefPtr<T_CppObject>::RefPtr(const RefPtr<T_CppObject>& src)
  229 :
  230   pCppObject_ (src.pCppObject_)
  231 {
  232   if(pCppObject_)
  233     pCppObject_->reference();
  234 }
  235 
  236 // The templated ctor allows copy construction from any object that's
  237 // castable.  Thus, it does downcasts:
  238 //   base_ref = derived_ref
  239 template <class T_CppObject>
  240   template <class T_CastFrom>
  241 inline
  242 RefPtr<T_CppObject>::RefPtr(const RefPtr<T_CastFrom>& src)
  243 :
  244   // A different RefPtr<> will not allow us access to pCppObject_.  We need
  245   // to add a get_underlying() for this, but that would encourage incorrect
  246   // use, so we use the less well-known operator->() accessor:
  247   pCppObject_ (src.operator->())
  248 {
  249   if(pCppObject_)
  250     pCppObject_->reference();
  251 }
  252 
  253 template <class T_CppObject> inline
  254 void RefPtr<T_CppObject>::swap(RefPtr<T_CppObject>& other)
  255 {
  256   const auto temp = pCppObject_;
  257   pCppObject_ = other.pCppObject_;
  258   other.pCppObject_ = temp;
  259 }
  260 
  261 template <class T_CppObject> inline
  262 RefPtr<T_CppObject>& RefPtr<T_CppObject>::operator=(const RefPtr<T_CppObject>& src)
  263 {
  264   // In case you haven't seen the swap() technique to implement copy
  265   // assignment before, here's what it does:
  266   //
  267   // 1) Create a temporary RefPtr<> instance via the copy ctor, thereby
  268   //    increasing the reference count of the source object.
  269   //
  270   // 2) Swap the internal object pointers of *this and the temporary
  271   //    RefPtr<>.  After this step, *this already contains the new pointer,
  272   //    and the old pointer is now managed by temp.
  273   //
  274   // 3) The destructor of temp is executed, thereby unreferencing the
  275   //    old object pointer.
  276   //
  277   // This technique is described in Herb Sutter's "Exceptional C++", and
  278   // has a number of advantages over conventional approaches:
  279   //
  280   // - Code reuse by calling the copy ctor.
  281   // - Strong exception safety for free.
  282   // - Self assignment is handled implicitely.
  283   // - Simplicity.
  284   // - It just works and is hard to get wrong; i.e. you can use it without
  285   //   even thinking about it to implement copy assignment whereever the
  286   //   object data is managed indirectly via a pointer, which is very common.
  287 
  288   RefPtr<T_CppObject> temp (src);
  289   this->swap(temp);
  290   return *this;
  291 }
  292 
  293 template <class T_CppObject>
  294   template <class T_CastFrom>
  295 inline
  296 RefPtr<T_CppObject>& RefPtr<T_CppObject>::operator=(const RefPtr<T_CastFrom>& src)
  297 {
  298   RefPtr<T_CppObject> temp (src);
  299   this->swap(temp);
  300   return *this;
  301 }
  302 
  303 template <class T_CppObject> inline
  304 bool RefPtr<T_CppObject>::operator==(const RefPtr<T_CppObject>& src) const
  305 {
  306   return (pCppObject_ == src.pCppObject_);
  307 }
  308 
  309 template <class T_CppObject> inline
  310 bool RefPtr<T_CppObject>::operator!=(const RefPtr<T_CppObject>& src) const
  311 {
  312   return (pCppObject_ != src.pCppObject_);
  313 }
  314 
  315 template <class T_CppObject> inline
  316 RefPtr<T_CppObject>::operator bool() const
  317 {
  318   return (pCppObject_ != nullptr);
  319 }
  320 
  321 #ifndef GLIBMM_DISABLE_DEPRECATED
  322 template <class T_CppObject> inline
  323 void RefPtr<T_CppObject>::clear()
  324 {
  325   reset();
  326 }
  327 #endif //GLIBMM_DISABLE_DEPRECATED
  328 
  329 template <class T_CppObject> inline
  330 void RefPtr<T_CppObject>::reset()
  331 {
  332   RefPtr<T_CppObject> temp; // swap with an empty RefPtr<> to clear *this
  333   this->swap(temp);
  334 }
  335 
  336 template <class T_CppObject>
  337   template <class T_CastFrom>
  338 inline
  339 RefPtr<T_CppObject> RefPtr<T_CppObject>::cast_dynamic(const RefPtr<T_CastFrom>& src)
  340 {
  341   const auto pCppObject = dynamic_cast<T_CppObject*>(src.operator->());
  342 
  343   if(pCppObject)
  344     pCppObject->reference();
  345 
  346   return RefPtr<T_CppObject>(pCppObject);
  347 }
  348 
  349 template <class T_CppObject>
  350   template <class T_CastFrom>
  351 inline
  352 RefPtr<T_CppObject> RefPtr<T_CppObject>::cast_static(const RefPtr<T_CastFrom>& src)
  353 {
  354   const auto pCppObject = static_cast<T_CppObject*>(src.operator->());
  355 
  356   if(pCppObject)
  357     pCppObject->reference();
  358 
  359   return RefPtr<T_CppObject>(pCppObject);
  360 }
  361 
  362 template <class T_CppObject>
  363   template <class T_CastFrom>
  364 inline
  365 RefPtr<T_CppObject> RefPtr<T_CppObject>::cast_const(const RefPtr<T_CastFrom>& src)
  366 {
  367   const auto pCppObject = const_cast<T_CppObject*>(src.operator->());
  368 
  369   if(pCppObject)
  370     pCppObject->reference();
  371 
  372   return RefPtr<T_CppObject>(pCppObject);
  373 }
  374 
  375 template <class T_CppObject> inline
  376 bool RefPtr<T_CppObject>::operator<(const RefPtr<T_CppObject>& src) const
  377 {
  378   return (pCppObject_ < src.pCppObject_);
  379 }
  380 
  381 template <class T_CppObject> inline
  382 bool RefPtr<T_CppObject>::operator<=(const RefPtr<T_CppObject>& src) const
  383 {
  384   return (pCppObject_ <= src.pCppObject_);
  385 }
  386 
  387 template <class T_CppObject> inline
  388 bool RefPtr<T_CppObject>::operator>(const RefPtr<T_CppObject>& src) const
  389 {
  390   return (pCppObject_ > src.pCppObject_);
  391 }
  392 
  393 template <class T_CppObject> inline
  394 bool RefPtr<T_CppObject>::operator>=(const RefPtr<T_CppObject>& src) const
  395 {
  396   return (pCppObject_ >= src.pCppObject_);
  397 }
  398 
  399 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
  400 
  401 /** @relates Glib::RefPtr */
  402 template <class T_CppObject> inline
  403 void swap(RefPtr<T_CppObject>& lhs, RefPtr<T_CppObject>& rhs)
  404 {
  405   lhs.swap(rhs);
  406 }
  407 
  408 } // namespace Glib
  409 
  410 
  411 #endif /* _GLIBMM_REFPTR_H */
  412 
  413 
  414 namespace
  415 {
  416 std::ostringstream result_stream;
  417 
  418 class Action : public sigc::trackable
  419 {
  420 public:
  421   Action() : ref_count(1) { }
  422 
  423   void reference() { ++ref_count; }
  424   void unreference() { if (--ref_count <= 0) delete this; }
  425 
  426   void emit_sig1(int n) { sig1.emit(n); }
  427 
  428   sigc::signal<void, int>& signal_sig1() { return sig1; }
  429 
  430 private:
  431   sigc::signal<void, int> sig1;
  432   int ref_count;
  433 
  434 };
  435 
  436 class Test : public sigc::trackable
  437 {
  438 public:
  439   Test()
  440   : action(new Action)
  441   {
  442     result_stream << "new Test; ";
  443 #ifdef ACTIVATE_BUG //See https://bugzilla.gnome.org/show_bug.cgi?id=564005#c14
  444     action->signal_sig1().connect(sigc::bind(sigc::mem_fun(*this, &Test::on_sig1), action));
  445 #else
  446     Glib::RefPtr<Action> action2(new Action);
  447     action->signal_sig1().connect(sigc::bind(sigc::mem_fun(*this, &Test::on_sig1), action2));
  448 #endif
  449   }
  450 
  451   ~Test()
  452   {
  453     result_stream << "delete Test; ";
  454   }
  455 
  456   void on_sig1(int n, Glib::RefPtr<Action> /* action */)
  457   {
  458     result_stream << "Test::on_sig1, n=" << n << "; ";
  459   }
  460 
  461   Glib::RefPtr<Action> action;
  462 
  463 }; // end Test
  464 
  465 } // end anonymous namespace
  466 
  467 int main(int argc, char* argv[])
  468 {
  469   auto util = TestUtilities::get_instance();
  470 
  471   if (!util->check_command_args(argc, argv))
  472     return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
  473 
  474   auto test = new Test;
  475 
  476   test->action->emit_sig1(23);
  477   delete test;
  478   util->check_result(result_stream, "new Test; Test::on_sig1, n=23; delete Test; ");
  479 
  480   return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
  481 }