Comparing C++ Standard Libraries libCstd and libstlport

 
By Mukesh Kapoor , Sun Studio Development Engineering, Sun Microsystems, May 17, 2006  
The Sun C++ compiler ships with two libraries that implement the C++ standard library: libCstd and libstlport.
  • libCstd is used by default and is based on Rogue Wave's stdlib 2.1.1.
  • libstlport is based on STLport version 4.5.3 and is used if you specify the compiler option -library=stlport4.
This article discusses the differences between the two libraries and explores the situations in which one library is preferred over the other.

Background

The Sun C++ compiler started shipping with the standard C++ library libCstd in the C++ 5.0 release of December 1998. Some of the newer language features such as member template classes, member template functions and partial specializations were not yet implemented in the compiler even though the C++ standard library uses all these language features. The libCstd headers use macros to enable or disable functionality in the library that rely on these features and the macros were defined to disable the functionality that uses the newer language features.

Later versions of the compiler implemented the new language features. However, in order to maintain binary compatibility with existing object files, the macros in the libCstd headers were not modified. As a result, the latest version of libCstd continues to have some missing functionality and some of the functions accept a different set of arguments than those that are specified in the standard.

The libstlport library was introduced in the C++ 5.4 release and uses all the language features needed by the library. No functionality in the library is suppressed because of any missing language features. As a result, the libstlport library conforms much more closely to the standard than libCstd does.

Disabled Language Features in libCstd

This section lists the different language features that are disabled in libCstd along with the corresponding missing functionality. Small test examples illustrate the missing features. The compiler issues errors for each test case if the default libCstd is used. All the test cases compile without errors if you specify -library=stlport4. Workarounds using the existing libCstd functionality are provided wherever possible.

Note: The following macros defined in the libCstd header stdcomp.h are used to disable functionality:

  • _RWSTD_NO_MEMBER_TEMPLATES
  • _RWSTD_NO_TEMPLATE_ON_RETURN_TYPE
  • _RWSTD_NO_MEM_CLASS_TEMPLATES
  • _RWSTD_NO_CLASS_PARTIAL_SPEC

Do not redefine any of the macros whose name starts with _RWSTD because doing so can result in a program that won't compile, won't link or won't run correctly. The reason for such problems is that the headers that are seen by a user program must match the headers that were used to build the libCstd that is linked to the program. By redefining the macro you introduce an inconsistency between the way the library was built and the way it's being used.

Language feature: Member Function Templates

The macro _RWSTD_NO_MEMBER_TEMPLATES is defined in libCstd to indicate that member template functions are not supported and the macro _RWSTD_NO_TEMPLATE_ON_RETURN_TYPE is defined to indicate that the compiler does not support the syntax for functions that are templatized only on the return type. As a result, the following functions are missing.

Missing Members of Class complex in <complex>

  • template <class X> complex<T>& operator= (const complex<X>& rhs);
  • template <class X> complex<T>& operator+= (const complex<X>& rhs);
  • template <class X> complex<T>& operator-= (const complex<X>& rhs);
  • template <class X> complex<T>& operator*= (const complex<X>& rhs);
  • template <class X> complex<T>& operator/= (const complex<X>&);

Example

The following test case does not compile with libCstd:

 % cat c1.c
            
#include <complex>
using namespace std;

struct X {
X(double x) { d = x; }
X& operator +=(double y) { d += y; return *this; }
double d;
};

main()
{
const complex<double> d1(1.0, 2.0);
const complex<double> d2(3.0, 4.0);
complex<X> d3;
d3 = d1;
d3 += d2;
}

% CC c1.c
"c1.c", line 15: Error: Cannot assign const std::complex<double> to
std::complex<X> without "std::complex<X>::operator=(const std::complex<X>&)";.
"c1.c", line 16: Error: The operation "std::complex<X> += const
std::complex<double>" is illegal.
2 Error(s) detected.

% CC -library=stlport4 c1.c
%

Workaround

Relpace the lines

 complex<X> d3;
            
d3 = d1;
d3 += d2;
 complex<double> temp = d1;
            
temp += d2;
complex<X> d3(temp.real(), temp.imag());

Missing Members of Class basic_string in <string>

In the list below, Typ can be one of: int, unsigned int, long, unsigned long, short, unsigned short, char, unsigned char, wchar_t, or bool. An entry containing Typ is actually ten entries with Typ replaced by each of these types in turn.

  • template <class InputIterator>
                    
    basic_string (InputIterator, InputIterator, const Allocator&);
  • basic_string (Typ n, charT c, const Allocator& alloc);
                    
  • template<class InputIterator>
                    
    basic_string<charT, traits, Allocator>& append (InputIterator, InputIterator);
  • basic_string<charT, traits, Allocator>& append (Typ n, charT c);
                    
  • template<class InputIterator>
                    
    basic_string<charT, traits, Allocator>& assign (InputIterator, InputIterator);
  • basic_string<charT, traits, Allocator>& assign (Typ n, charT c);
                    
  • template<class InputIterator>
                    
    void insert (iterator, InputIterator, InputIterator);
  • void insert (iterator p, Typ n, charT c);
                    
  • template<class InputIterator>
                    
    basic_string<charT, traits, Allocator>& __replace_aux (
    iterator first1,
    iterator last1,
    InputIterator first2,
    InputIterator last2);
  • template<class InputIterator>
                    
    basic_string<charT, traits, Allocator>& replace (iterator, iterator, InputIterator, InputIterator);
  • basic_string<charT, traits, Allocator>& replace (iterator first, iterator last, Typ n, charT c);
                    

Example

 % cat s1.c
            
#include <string>
#include <list>
using namespace std;

int main()
{
string s1("abcd");
list<char> l1;
l1.push_back('e');
l1.push_back('f');
string s2 = s1.append( l1.begin(), l1.end() );
}

% CC s1.c
"s1.c", line 11: Error: Could not find a match for std::string::append
(std::list<char>::iterator, std::list<char>::iterator) needed in main().
1 Error(s) detected.

Workaround

Relpace the line

 string s2 = s1.append( l1.begin(), l1.end() );
 string s2(s1);
            
for( list<char>::iterator i = l1.begin(); i != l1.end(); ++i )
s2 += *i;

Missing Member of Class pair in <utility>

  • template<class U, class V> pair(const pair<U, V> &p);

Example

 % cat p1.c
            
#include <utility>

struct S {
S() { val = 0; }
S(int i) { val = i; }
int val;
};

main()
{
std::pair<int, int> p1(1, 2);
std::pair<S, int> p2 = p1;
}

% CC p1.c
"p1.c", line 12: Error: Cannot use std::pair<int, int> to initialize std::pair<S, int>.
1 Error(s) detected.

Workaround

Relpace the line

 std::pair<S, int> p2 = p1;
 std::pair<S, int> p2(p1.first, p1.second);

Missing members of class locale in <locale>

  •  // creating locale based on other locales:
                    
    template <class Facet> locale (const locale& other,Facet* f);
  •  // assignment:
                    
    template <class Facet> locale combine(const locale& other);
  •  // sorting of strings:
                    
    template <class charT, class Traits, class Allocator>
    bool operator() (const basic_string<charT,Traits,Allocator>& s1,
    const basic_string<charT,Traits,Allocator>& s2) const;
  •  // facet access:
                    
    template <class Facet> const Facet& use_facet (const locale&);
    template <class Facet> inline bool has_facet (const locale&) throw();

Example

 % cat l1.c
            
#include <locale>
using namespace std;

main()
{
locale loc1("C");
locale loc2("de");
locale loc3 = loc1.combine<numpunct<char> >(loc2);
const time_get<char>& f = use_facet<time_get<char> >(loc1);
}

% CC l1.c
"l1.c", line 8: Error: Unexpected type name "std::numpunct<char>" encountered.
"l1.c", line 8: Error: combine is not a member of std::locale.
"l1.c", line 9: Error: Could not find a match for std::use_facet<std::Facet>
(std::locale) needed in main().
3 Error(s) detected.

Missing Members of Class auto_ptr in <memory>

  • template <class Y> operator auto_ptr_ref<Y>();
                    
  • template <class Y> operator auto_ptr<Y>();
                    
  • template <class Y>
                    
    auto_ptr(auto_ptr<Y>&);
  • template <class T>
                    
    inline pair<T*, ptrdiff_t> get_temporary_buffer (ptrdiff_t len);

Example

 % cat a1.c
            
#include <memory>

struct A {};
struct B : public A {};

main()
{
std::auto_ptr<B> b(new B);
std::auto_ptr<A> a(b);
}

% CC a1.c
"a1.c", line 9: Error: Cannot use std::auto_ptr<B> to initialize std::auto_ptr<A>.
1 Error(s) detected.

Missing Members of Class bit_set in <bitset>

  •                  
    template <class charT, class traits, class Allocator>
                    
    basic_string<charT,traits,Allocator> to_string () const;

Example

 % cat b1.c
            
#include <bitset>
#include <iostream>
using namespace std;

int main()
{
bitset<7> b(4);
string s = b.to_string<char, char_traits<char>, allocator<char> >();
cout << "s = " << s << endl;
}

% CC b1.c
"b1.c", line 8: Error: Badly formed expression.
"b1.c", line 8: Error: "char_traits" cannot be declared as an object or function.
"b1.c", line 8: Error: "allocator" cannot be declared as an object or function.
"b1.c", line 8: Error: "," expected instead of ">".
4 Error(s) detected.

Workaround

Replace the line

  
            
string s = b.to_string<char, char_traits<char>, allocator<char> >();
            
  
            
string s = b.to_string();.
            

Language Feature: Member Template Classes

The macro _RWSTD_NO_MEM_CLASS_TEMPLATES is defined to indicate that the compiler does not support member template classes. As a result, the following class and constructor are not defined in <memory>:

  • template <class Y> class auto_ptr_ref{};
  • auto_ptr(auto_ptr_ref<X>&);

Example

 % cat a2.c
            
#include <memory>
using namespace std;

class A {};
class B : public A {};

main()
{
auto_ptr_ref<A>(auto_ptr<B>::*pf)() =
&auto_ptr<B>:: operator auto_ptr_ref<A>;
}

% CC a2.c
"a2.c", line 9: Error: auto_ptr_ref is not defined.
"a2.c", line 9: Error: Unexpected type name "A" encountered.
"a2.c", line 9: Error: Identifier expected instead of "*".
"a2.c", line 9: Error: pf is not defined.
"a2.c", line 10: Error: An overloadable operator was expected instead of "auto_ptr_ref".
"a2.c", line 10: Error: auto_ptr_ref is not a member of std::auto_ptr<B>.
"a2.c", line 10: Error: Unexpected type name "A" encountered.
"a2.c", line 10: Error: Operand expected instead of ";".
8 Error(s) detected.

Language Feature: Partial Specializations

The macro _RWSTD_NO_CLASS_PARTIAL_SPEC is defined to indicate that the compiler does not support partial specialization of template classes with default parameters. As a result, the following global functions are missing in <algorithm>.

  • count()
  • count_if()

Example

 % cat c2.c
            
#include <algorithm>
#include <list>
#include <iostream>
#include <iterator>
using namespace std;

bool gtr3(int n)
{
return (n > 3);
}

main()
{
// count elements in a list
list<int> x;

for (int i = 0; i < 10; i++)
x.push_back(i);

cout << "list: ";
copy (x.begin(), x.end(), ostream_iterator<int>(cout, " "));
cout << endl;

int n1 = count(x.begin(), x.end(), 6); // # elements with value 6
int n2 = count_if(x.begin(), x.end(), gtr3); // # elements with value >3

cout << "n1 = " << n1 << endl;
cout << "n2 = " << n2 << endl;
}

% CC c2.c
"c2.c", line 23: Error: Could not find a match for std::count<std::InputIterator, std::T, std::Size>
(std::list<int>::iterator, std::list<int>::iterator, int) needed in main().
"c2.c", line 24: Error: Could not find a match for std::count_if<std::InputIterator, std::Predicate, std::Size>
(std::list<int>::iterator, std::list<int>::iterator, bool(int)) needed in main().
2 Error(s) detected.

Workaround

Relpace the lines

 int n1 = count(x.begin(), x.end(), 6); // # elements with value 6
            
int n2 = count_if(x.begin(), x.end(), gtr3); // # elements with value >3
 int n1 = 0;
            
int n2 = 0;
count(x.begin(), x.end(), 6, n1); // # elements with value 6
count_if(x.begin(), x.end(), gtr3, n2); // # elements with value >3

Missing Template Classes in <iterator>

  • template <class Iterator> struct iterator_traits {}
  • template <class T> struct iterator_traits<T*> {}
  • template <class T> struct iterator_traits<const T*> {}

Example

 % cat i1.c
            
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;

main()
{
vector<int> v(10);

for (int i = 0; i < 10; i++)
v[i] = i;

iterator_traits<int>::value_type x = v[5];
cout << "vector: ";
copy (v.begin(), v.end(), ostream_iterator<int>(cout, " "));
cout << endl;
cout << "x = " << x << endl;
}

% CC i1.c
"i1.c", line 13: Error: iterator_traits is not defined.
"i1.c", line 13: Error: Badly formed expression.
"i1.c", line 17: Error: x is not defined.
3 Error(s) detected.

Workaround

Relpace the line

  
            
iterator_traits<int>::value_type x = v[5];
          
  
            
int x = v[5];
          

Which Library Should You Use?

The Sun C++ compiler uses libCstd by default. If binary compatibility with existing object files is required, or if the application links with several other libraries that were built using libCstd then libCstd should be used for building the application. The drawback is that the application cannot use the features that are missing in libCstd.

libstlport provides an implementation that is much closer to the standard. If an application needs the functionality that is missing in libCstd then libstlport can be used. However, note that both libCstd and libstlport cannot be used in the same application. If the application is built with -library=stlport4 then all libraries that are linked with the application and that use the standard C++ library functions should also be built with -library=stlport4. This may not always be possible if some third party libraries are used. The user may have to ask the third party vendors to provide libraries built with -library=stlport4.

Another reason to use libstlport may be for better performance. Some of the classes in libstlport have a better performance compared to libCstd. Since the performance of an application depends on several factors, it may be best to try using each library in turn and measure the performance and then use the library that provides the best results.

Summary

  • libCstd does not support all the features of the standard library.
  • libstlport conforms more closely to the C++ standard.
  • Use libCstd if you desire binary compatibility with existing object files.
  • Use libstlport if your application needs the missing functionality of libCstd.
  • In some cases, libstlport may provide better performance.

References

  1. Nicolai M. Josuttis, The C++ Standard Library, Addison-Wesley, 1999
  2. Bjarne Stroustrup, The C++ Programming Language, Addison-Wesley, 1997
Left Curve
System Administrator
Right Curve
Left Curve
Developer and ISVs
Right Curve
Left Curve
Related Products
Right Curve
solaris-online-forum-banner