Difference between revisions of "Code/CodeSnippetsCollection"

From Apache OpenOffice Wiki
Jump to: navigation, search
 
m (Example:)
 
(10 intermediate revisions by 5 users not shown)
Line 46: Line 46:
  
 
Code:  
 
Code:  
<pre>
+
<syntaxhighlight lang="cpp">
 
template<typename T>  
 
template<typename T>  
 
class qualified_ptr
 
class qualified_ptr
Line 70: Line 70:
 
             T* mP;
 
             T* mP;
 
};  
 
};  
</pre>
+
</syntaxhighlight>
  
 
Discussion:
 
Discussion:
Line 79: Line 79:
  
 
----
 
----
 +
 
=== General C++: ===
 
=== General C++: ===
 
'''Try&ndash;Finally in C++'''
 
'''Try&ndash;Finally in C++'''
  
 
C++ does not offer a try&ndash;finally construct (as, e.g., Java does):
 
C++ does not offer a try&ndash;finally construct (as, e.g., Java does):
<pre>
+
<syntaxhighlight lang="cpp">
 
try {
 
try {
 
   do_something;
 
   do_something;
Line 89: Line 90:
 
   clean_up;
 
   clean_up;
 
}
 
}
</pre>
+
</syntaxhighlight>
 
would first try to execute <code>do_something</code>, and then always execute <code>clean_up</code>, regardless of whether the execution of <code>do_something</code> succeeded or failed by throwing an exception.
 
would first try to execute <code>do_something</code>, and then always execute <code>clean_up</code>, regardless of whether the execution of <code>do_something</code> succeeded or failed by throwing an exception.
  
Line 97: Line 98:
  
 
(1) Simulate try&ndash;finally with try&ndash;catch-all:
 
(1) Simulate try&ndash;finally with try&ndash;catch-all:
<pre>
+
<syntaxhighlight lang="cpp">
 
try {
 
try {
 
   do_something;
 
   do_something;
Line 105: Line 106:
 
}
 
}
 
clean_up;
 
clean_up;
</pre>
+
</syntaxhighlight>
 
This solution has the disadvantage that it duplicates code, in that <code>clean_up</code> must be executed in both the catch handler and the normal program flow.
 
This solution has the disadvantage that it duplicates code, in that <code>clean_up</code> must be executed in both the catch handler and the normal program flow.
  
 
(2) Use resource-acquisition-is-initialization:
 
(2) Use resource-acquisition-is-initialization:
<pre>
+
<syntaxhighlight lang="cpp">
 
namespace {
 
namespace {
 
class CleanUp {
 
class CleanUp {
Line 125: Line 126:
 
   do_something;
 
   do_something;
 
}
 
}
</pre>
+
</syntaxhighlight>
 
This solution has the disadvantage that you need an extra class, which makes it very verbose.  Sometimes, however, the <code>clean_up</code> code is so general that it can be placed in a public helper class (e.g., <code>osl::MutexGuard</code>).
 
This solution has the disadvantage that you need an extra class, which makes it very verbose.  Sometimes, however, the <code>clean_up</code> code is so general that it can be placed in a public helper class (e.g., <code>osl::MutexGuard</code>).
  
 
When you are using solution 1, and you also have to catch and handle exceptions thrown from <code>do_something</code>, it is best to introduce two try blocks, the inner one simulating the try--finally, the outer one catching and handling the exceptions:
 
When you are using solution 1, and you also have to catch and handle exceptions thrown from <code>do_something</code>, it is best to introduce two try blocks, the inner one simulating the try--finally, the outer one catching and handling the exceptions:
<pre>
+
<syntaxhighlight lang="cpp">
 
try {
 
try {
 
   try {
 
   try {
Line 143: Line 144:
 
   throw Exception3();
 
   throw Exception3();
 
}
 
}
</pre>
+
</syntaxhighlight>
  
 
Discussion:
 
Discussion:
Line 162: Line 163:
  
 
Conditions for use: See limitations above. You should use this helper as follows:
 
Conditions for use: See limitations above. You should use this helper as follows:
<pre>
+
<syntaxhighlight lang="cpp">
 
uno::Sequence< t >( MakeSequence< t >( t_1 )( t_2 )...( t_n ) );
 
uno::Sequence< t >( MakeSequence< t >( t_1 )( t_2 )...( t_n ) );
</pre>
+
</syntaxhighlight>
 
which just serves to illustrate the idea. Really useful is the following scenario:
 
which just serves to illustrate the idea. Really useful is the following scenario:
<pre>
+
<source lang="cpp">
 
callUNOMethod( MakeSequence< t >( t_1 )( t_2 )...( t_n ) );
 
callUNOMethod( MakeSequence< t >( t_1 )( t_2 )...( t_n ) );
</pre>
+
</source>
 
where callUNOMethod take the obvious parameter.
 
where callUNOMethod take the obvious parameter.
  
 
Code:
 
Code:
<pre>
+
<syntaxhighlight lang="cpp">
 
template < typename T >
 
template < typename T >
 
class MakeSequence : public ::com::sun::star::uno::Sequence< T >
 
class MakeSequence : public ::com::sun::star::uno::Sequence< T >
Line 189: Line 190:
 
     }
 
     }
 
};
 
};
</pre>
+
</syntaxhighlight>
  
 
You can find this helper and a few more for other container types in comphelper/InlineContainer.hxx
 
You can find this helper and a few more for other container types in comphelper/InlineContainer.hxx
  
 
----
 
----
 +
 
=== UNO: ===
 
=== UNO: ===
 
'''Exception-safe UNO event broadcasting from office core'''
 
'''Exception-safe UNO event broadcasting from office core'''
Line 199: Line 201:
 
Problem solved: When broadcasting UNO events from within our Office core, most often
 
Problem solved: When broadcasting UNO events from within our Office core, most often
 
something similar to the code below happens:
 
something similar to the code below happens:
<pre>
+
<syntaxhighlight lang="cpp">
 
OInterfaceIteratorHelper aListenerIterator( maListeners );
 
OInterfaceIteratorHelper aListenerIterator( maListeners );
 
while( aListenerIterator.hasMoreElements() )
 
while( aListenerIterator.hasMoreElements() )
 
     aListenerIterator.next()->listenerMethod();
 
     aListenerIterator.next()->listenerMethod();
</pre>
+
</syntaxhighlight>
 
The problem with this code is that listeners might throw
 
The problem with this code is that listeners might throw
 
exceptions. As I'm talking about core broadcasts here, this is usually
 
exceptions. As I'm talking about core broadcasts here, this is usually
Line 224: Line 226:
  
 
Code:
 
Code:
<pre>
+
<syntaxhighlight lang="cpp">
 
// Listener iterator transparently handles threading issues,
 
// Listener iterator transparently handles threading issues,
 
// no need for explicit locking here
 
// no need for explicit locking here
Line 265: Line 267:
 
     }
 
     }
 
}
 
}
</pre>
+
</syntaxhighlight>
  
  
[[Category:CodeSnippets]]
+
[[Category:Cpp]]
 +
[[Category:Snippet]]
 +
[[Category:API]]

Latest revision as of 12:00, 15 May 2021

This page is intended to contain:

Examples or pieces of code, which have proved so far to be the best known way, to solve a specific problem. It's supposed to present solutions for problems often faced during coding. So, brilliant but too-specific-to-be-reusable inventions are not intended to be here.

A snippet entry should list the use cases and limitations of the code presented, and the code itself, or a link to the file where it is implemented. If there are further runtime requirements, such as linking to a specific library, that must be noted, too.


This page contains C++-code as this is our main development language. See at bottom of page for other languages.


Example:

Constness Transitive Pointer Class

Problem solved: As a matter of fact, pointer (and references) as class members can model two kinds of relationships: Either the pointee is part of the pointer holder's state, just as for ordinary member variables. A special case of this is the "contains" relation, where the object owns the pointee. Or the pointer models a "uses" relation, i.e. holding a pointer only for informational reasons, because the two objects e.g. cooperate. In the first case, constness should be transitive, i.e. calling non-const methods on the pointee should not be allowed within const methods of the pointer holder. This leads to identical behaviour (and compiler warnings) as for ordinary members. In the second case, constness should not be transitive, since the pointee does not belong to the object's state (if it does, you should check whether it also belongs to the object's visible state. If yes, make constness transitive). Normal C++ pointer and references model only the second case, but a simple template accounts for the first.

Limitations: You have to think before you apply this. Furthermore, this class does not impose any ownership semantics on the wrapped pointer, use auto_ptr or Dyn for that purpose. The template parameter must be a "first class type", i.e. not a reference to something.

Conditions for use: See motivation above. Generally, declare your methods const and make your pointer members const-transitive, until the compiler complains. Then check if it's your mistake or a case for mutable, or if a simple plain pointer is what you wanted.

Code:

template<typename T> 
class qualified_ptr
{
public:
        // lifecycle
        qualified_ptr( T* p ) : mP ( p ) {}
 
        // we're content with compiler-generated defaults here:
        // ~qualified_ptr();
        // qualified_ptr( const qualified_ptr<T>& ) 
        // qualified_ptr<T>& operator=( const qualified_ptr<T>& ); 
 
        // operations
  qualified_ptr& operator=( T* p )   { mP = p; return *this; }
        T*       operator->()        { return mP; }
  const T*       operator->() const  { return mP; }
        T&       operator*()         { return *mP; }
  const T&       operator*() const   { return *mP; }
        bool     operator!() const   { return !mP; }
 
private:
             T* mP;
};

Discussion:

SB: Isn't Constness Transitive Pointer Class a rather confusing example for what a code snippet is? In my opinion, a code snippet should be a piece of code which will be written (in slightly modified form) in many places. But the template qualified_ptr should be written down in only one place (e.g., a helper library). It should be emphasized that in this case, not the code of qualified_ptr itself is the code snippet, but rather the use of qualified_ptr when declaring class members.

DR: May be useful: operator!()


General C++:

Try–Finally in C++

C++ does not offer a try–finally construct (as, e.g., Java does):

try {
  do_something;
} finally {
  clean_up;
}

would first try to execute do_something, and then always execute clean_up, regardless of whether the execution of do_something succeeded or failed by throwing an exception.

Note that clean_up should generally be written so that it itself does not throw any exceptions.

There are two solutions in C++.

(1) Simulate try–finally with try–catch-all:

try {
  do_something;
} catch (...) {
  clean_up;
  throw;
}
clean_up;

This solution has the disadvantage that it duplicates code, in that clean_up must be executed in both the catch handler and the normal program flow.

(2) Use resource-acquisition-is-initialization:

namespace {
class CleanUp {
public:
  inline CleanUp() {}
  inline ~CleanUp() { clean_up; }
private:
  CleanUp(CleanUp &); // not implemented
  void operator =(CleanUp); // not implemented
};
}
 
{
  CleanUp c;
  do_something;
}

This solution has the disadvantage that you need an extra class, which makes it very verbose. Sometimes, however, the clean_up code is so general that it can be placed in a public helper class (e.g., osl::MutexGuard).

When you are using solution 1, and you also have to catch and handle exceptions thrown from do_something, it is best to introduce two try blocks, the inner one simulating the try--finally, the outer one catching and handling the exceptions:

try {
  try {
    do_something;
  } catch (...) {
    clean_up;
    throw;
  }
  clean_up;
} catch (Exception1 & e) {
  handle_e;
} catch (Exception2 &) {
  throw Exception3();
}

Discussion:


Inline Container for UNO sequence (after Alexandrescu)

Problem solved: Creating a fixed size UNO sequence, with entries known at compile time, tends to be a little bit clumsy. There has always an automatic object to be generated, and the entries manually assigned. This snippet proposes a much more dynamic solution, which creates a temporary. Furthermore, as it is an expression, not a statement, it can be used much more versatilly.

Limitations: For every container class you want this applied to, you need an explicit wrapper implementation. Furthermore, currently there's at least one extra copy operation involved, so you better use this only for small sequences.

Conditions for use: See limitations above. You should use this helper as follows:

uno::Sequence< t >( MakeSequence< t >( t_1 )( t_2 )...( t_n ) );

which just serves to illustrate the idea. Really useful is the following scenario:

callUNOMethod( MakeSequence< t >( t_1 )( t_2 )...( t_n ) );

where callUNOMethod take the obvious parameter.

Code:

template < typename T >
class MakeSequence : public ::com::sun::star::uno::Sequence< T >
{
public:
    explicit MakeSequence(const T &a)
        : ::com::sun::star::uno::Sequence< T >( 1 )
    {
        this->operator[](0) = a;
    }
    MakeSequence& operator()(const T &a)
    {
        this->realloc( this->getLength() + 1 );
        this->operator[]( this->getLength() - 1 ) = a;
        return *this;
    }
};

You can find this helper and a few more for other container types in comphelper/InlineContainer.hxx


UNO:

Exception-safe UNO event broadcasting from office core

Problem solved: When broadcasting UNO events from within our Office core, most often something similar to the code below happens:

OInterfaceIteratorHelper aListenerIterator( maListeners );
while( aListenerIterator.hasMoreElements() )
    aListenerIterator.next()->listenerMethod();

The problem with this code is that listeners might throw exceptions. As I'm talking about core broadcasts here, this is usually the last chance to catch exceptions before they crash the office.

Limitations: Catching every exception propagating from the listeners is not always valid. In larger contexts, a listener might throw an exception that is meant for a third object, e.g. if the component at hand is only mediating between two objects. Thus, the second catch statement might be removed. Although, unless you're absolutely sure what you're doing, and especially if you're not a UNO component yourself, any exception must be caught. Failing to do so enables every component to crash the office by simply throwing an uno::Exception.

Conditions for use: considerations above are only valid for event broadcaster within the Office core, not for UNO programming in general.

Code:

// Listener iterator transparently handles threading issues,
// no need for explicit locking here
::cppu::OInterfaceIteratorHelper aIter( maListeners );
while( aIter.hasMoreElements() )
{
    // This querying might not be necessary, in case you have put only
    // references of a distinct type into the container, you may directly
    // cast the pointer returned by aIter.next().
    uno::Reference < XEventListener > xListener( aIter.next(),
                                                 uno::UNO_QUERY ); 
    if( xListener.is() )
    {
        try
        {
            xListener->listenerMethod();
        }
        catch( const lang::DisposedException& e )
        {
            // DisposedExceptions from the listener might indicate a
            // broken connection to a different environment.
            OSL_ENSURE(e.Context.is(), "caught dispose exception with"
                                       "empty Context field"); 
            // If the exception stems from the listener then remove it
            // from the list of listeners.  If the Context field of the
            // exception is empty this is interpreted to indicate the
            // listener as well.
            if( e.Context == xListener || !e.Context.is() )
                aIter.remove();
        }
        catch( const uno::Exception& e )
        {
            // catch-all for everything else. You might want to narrow
            // the exception type caught here, if your listener
            // interface does specify it.
            OSL_TRACE("exception %s from listener caught", 
                      ::rtl::OUStringToOString( e.Message,
                                                RTL_TEXTENCODING_ASCII_US ).getStr() ); 
        }
    }
}
Personal tools