Home
Fractals
Tutorials
Books
My blog
My LinkedIn Profile

BOOKS i'm reading

Napoleon Hill Keys to Success: The 17 Principles of Personal Achievement, Napoleon Hill, ISBN: 978-0452272811
The 4-Hour Workweek: Escape 9-5, Live Anywhere, and Join the New Rich (Expanded and Updated), Timothy Ferriss, ISBN: 978-0307465351
The Fountainhead, Ayn Rand, ISBN: 0452273331
Web Hosting Canada

mailto:olivier@olivierlanglois.net

08/26/07

Permalink 08:39:43 pm, by lano1106, 327 words, 6039 views   English (CA)
Categories: C++

Using integral constant template parameters

One usage of them commonly demonstrated in C++ Templates textbooks such as C++ Templates is when you want to control the maximum capacity of a container like this:

template< typename T, int MAXSIZE >
class stack
{
...
   private:
   T m_array[MAXSIZE];
};

I have found another very useful property of integral constant template parameters. You can define a class template with an integral constant template parameter and not use it at all in the declaration:

template<int i>
class Unique
{
  public:
  static int var;
};

template<int i>
int Unique<i>::var;

The property of this template is that a distinct var variable will be created for each instantiation of the template:

Unique<1234>::var = 1;
Unique<0>::var = 2;

and so on. By itself, it is more or less useful but imagine that you are dealing with a function registering a callback function that does not let you provide a parameter that will be passed to the callback function but your callback needs to access variables and you must provide more than 1 callback function and each of them needs to access its own set of variables. You could do it by hand by writing x different callbacks and create x sets of variables with different names but by doing that, you would be polluting your namespace and that would be a very long task for nothing. Instead, a class template with an integral constant parameter is the right tool for this situation:

template<int i>
class CB
{
  public:
  static void SetCBParams(int x1, int x2)
  { m_x1 = x1; m_x2 = x2; }
  static void CBFunc();
  private:
  static int m_x1;
  static int m_x2;
};

template<int i>
int CB<i>::m_x1;
template<int i>
int CB<i>::m_x2;

and then

CB<1>::SetParam(1,2);
registerCB(&CB<1>::CBFunc);
CB<2>::SetParam(3,4);
registerCB(&CB<2>::CBFunc);
...

08/22/07

Permalink 10:07:44 pm, by lano1106, 426 words, 4286 views   English (CA)
Categories: C++

explicit destructor call in templates

Sometimes efficient memory management is needed and to accommodate that need, the C++ language provides the placement new operator to let the user specify the location where an object is going to be instantiated. When the placement new operator is used, the user must then explicitly call the destructor.

This is all fine but I have been wondering what happens when the placement new operator is used in conjunction with templates such as in the std::vector container and when the template parameter is a scalar built-in type that obviously does not have a destructor.

I have found out that the C++ standard committee envisaged the situation and has included specification of what a compiler must do in such situation. I do not have a copy of the standard text but the section 5.2.4 (Pseudo destructor call) states that the expression p->~T() becomes a pseudo destructor call for a built-in pointer type, which does nothing.

Here is a small program that I have successfully compiled to verify that pseudo destruction works fine:

#include <iostream>

// The header file containing the declaration of the placement new operator
// according to 'The C++ Programming Language' book (section 10.4.11) but it
// compiles fine without. It must be because it is included from <iostream>
#include <new>

class TestClass
{
    public:
    TestClass() : m_x(3) {}
    ~TestClass()
    { std::cout << "TestClass destructor called"
                << std::endl; }
    void print() const
    { std::cout << "Hello " << m_x
                << std::endl; }
    private:
    int m_x;
};

template<typename T>
class PseudoTest
{
    public:
    PseudoTest() { m_pObj = new(m_buf) T; }
    ~PseudoTest() { m_pObj->~T(); }
    T *m_pObj;
    private:
    char m_buf[sizeof(T)];
};

int main(int argc, char *argv[])
{
    // First test the int case
    {
        PseudoTest<int> a;
        *a.m_pObj = 777;
        std::cout << *a.m_pObj << std::endl;
    }
    // Then if something prints out, that means that the 
    // int pseudo-destructor has been called successfully.
    {
        PseudoTest<TestClass> b;
        b.m_pObj->print();
    }
    return 0;
}

One final word, note that I have used the placement new operator on a char buffer located on the stack and, according to Herb Sutter, this is a very bad thing because this generates non portable code. He explains why in his book Exceptionnal C++ (item 30: The "Fast Pimpl" Idiom) and then presents the right way to do it but since my test program compiles and runs fine, my evil code is will be fine for the demonstration purpose of this blog entry.

08/19/07

Permalink 01:04:58 pm, by lano1106, 426 words, 6529 views   English (CA)
Categories: C++

Dependent names and Two-Phase Lookup

Question:

What is wrong in this code from the book 'The C++ Programming Language', section 3.7.2? and why does MSVC accept it and not GCC?

// Range checking vector 
template< class T > class Vec : public std::vector< T >
{ 
public: 
  Vec () : std::vector< T > () { } 
  Vec (int s) : std::vector< T > (s) { } 

  // Range checking by using the at () method,
  // which throws out_of_range 
  T& operator[] (int i) { return at (i); } 
  const T& operator[] (int i) const { return at (i); } 
};

GCC reports this error:

since at() doesn't depend on any template parameters it should be available

Answer:

A compliant compiler will partially validate the template code that does not depend on the template parameters and complete the validation at the template instantiation point. It is that way because code depending on template parameter could have a totally different meaning if between the template declaration and the Point of instantiation (POI) there is a template specialization.

When you call a member function from a template base class, the way it is written is making the name nondependent. To fix the code, 2 options are available. You can either write:

  • this->at(i)
  • std::vector<T>::at(i)

1. is preferred as it will work as expected if the function called is virtual.

If VC++ does not complain, it is because it simply does not support the two phase lookup and compile templates only at instantiation point. GCC is a better compiler in that aspect because it complies with the C++ standard by implementing the Two-Phase lookup. You can easily fool VC++ with the following code:

template <class T> 
class Test 
{ 
public: 
   void Test() { foo(); } 
private: 
   T m_a; 
} 

// Non dependent function declared after
// template declaration
int foo();

int main(int argc, char *argv[]) 
{ 
    Test<int> testObj; 
    testObj.Test(); 
    return 0; 
}

GCC will generate an error when encountering the template complaining that foo() is not declared but VC++ will happily accept this code. Now that this is explained, note that except annoyance when porting code from VC++ to GCC or any other standard compliant compiler, the only consequence for MSVC of not being totally C++ standard compliant by not supporting the Two-Phase lookup is that if there are errors in a template, the compiler will delay their report at its instantiation instead of reporting them as soon as the template is encountered.

If you would like to explore further Dependant base classes, Point of Instantiation (POI) and Two-Phase lookup, I highly recommend to consult the book C++ Templates.

08/15/07

Permalink 09:26:37 pm, by lano1106, 336 words, 3586 views   English (CA)
Categories: Linux/UNIX, Multithreading

Pthreads Programming: A POSIX Standard for Better Multiprocessing

Pthreads Programming: A POSIX Standard for Better Multiprocessing, Bradford Nichols, Dick Buttlar, Jacqueline Proulx Farrell, ISBN: 1565921151

This book does a nice job for describing the pthread API. When I have read this book, my multithread programming experience was mainly with Win32 threads and reading this book was my first exposure to the condition synchronization objects. With the help of this book, it has been a breeze to learn how to use conditions. What is missing from this book written 10 years ago, which is also missing in all multithread books that I have read of that era, is coverage on issues with parallel processing. If all you have to do with threads is to launch a background job while keeping UI responsive or asynchronous I/O on a single core processor, you will be fine with this book.

However, if you try to crunch an array of data with multiple threads each processing their own chunk of the array, you could fall into cache line alignment problems even if your threads does not access the same memory locations. Those problems are platform dependant. I have written such a program that was working wonderfully well with a Sparc station and a PowerPC based station but once ported to a x86 architecture, the program was actually becoming slower than the single thread version. It is very hard to get it right. You have to be careful about the array alignment in memory and where the boundaries of the chunks of data that you assign to threads are. What will happen if 2 threads located on 2 different processors access to the same cache line is that one processor will have to flush that cache line back to the main memory and the other processor will have to fetch the values back from the main memory to its cache. The overhead of this is so huge that processing the array from a single thread could be faster.

I still have to find a book that addresses these problems. I expect it to come soon with dual and quad core processors becoming mainstream but this is not this book.

08/13/07

Permalink 10:44:30 pm, by lano1106, 90 words, 3504 views   English (CA)
Categories: TCP/IP, TCP/IP

Effective TCP/IP Programming: 44 Tips to Improve Your Network Programs

Effective TCP/IP Programming: 44 Tips to Improve Your Network Programs, Jon C. Snader, ISBN: 0201615894

Not all of the 44 tips are exceptional. Some of them are pretty trivial such as "Read Stevens books" or "consult RFCs" but about 35 tips are very good. The author knows well this topic and explains very well the reasons behind these tips. I am sure that all these good tips can be found in the TCP/IP Illustrated books but if you do not have the time to read 3 volumes consisting of about 2000 pages, this less than 300 pages book will provide a nice synthesis of TCP/IP programming good practices.

<< Previous Page :: Next Page >>

Olivier Langlois's blog

I want you to find in this blog informations about C++ programming that I had a hard time to find in the first place on the web.

< Previous | Next >

December 2024
Sun Mon Tue Wed Thu Fri Sat
 << <   > >>
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        

Search

Custom Search

Misc

XML Feeds

What is RSS?

Who's Online?

  • Guest Users: 2

powered by
b2evolution