vijayan121 1,152 Posting Virtuoso

>> First of all the application gets too slow, from the fifth iteration and above...
ok, this happens on my machine too, though not from the fifth iteration, but the core dump occurs later at about the 11th or 12th iteration. increasing the sysctl for max memory per process (in /boot/loader.conf in feebsd) does seem to remove that, but that only masks the problem; it will resurface at some higher iteration. and the slowing down continues to happen.

>> if the desktop environment downs't get stack i get a core dumped error...
no matter what happens in your program, the machine or the desktop environment has no business getting stuck. which linux distro are you using? even if you do want to use linux, you would be better of switching to a distro like slackware or debian where you would be unlikely to get into such problems. and from what i've seen so far, avoid the (unfortunately popular) *buntu disasters.

>> Any ideas? What can it be...i mean with fewer iterations i don't get any problem, and everything works like it should, also valgrind reports that i don't have any memory leak... Why i get these results with some more iterations?
i've only had a cursory look at the problem; my suspicion right now is in the boost::pool<> implementation. i can't say this with any confidence at all (and may be completely wrong); really need more time to investigate it.and come to a definite conclusion. …

vijayan121 1,152 Posting Virtuoso

>> 1 million elements, 38 ms
that seems reasonable. what were the compiler switches? and i suppose it with the use of boost.pool?

>> it seems weird {that the destructor doesn't do anything} because if the nodes remain and there isn't any leftist heap to contain them{i.e. i didn't merge, but just created a queue and then deleted it...} then this is not considered as a memory leak
not really. the heaps are merged in pairs and put back into the queue till only one node remains. the pointer to the root node of the last heap in the queue (the one that contains the fully merged heap) is copied to the member variable root of the heap pointed to by the this pointer. so even if the queue (and the heap that it contains) are destroyed, the nodes remain. till you call boost::pool::purge_memory().

>>> daniweb does not seem to allow uploads of tar.gz or tar.bz2 files
let me try something. great, this works! note: fool_daniweb.txt is *not* a text file; it is really a tar.bz2

vijayan121 1,152 Posting Virtuoso

>> root = merge( q.front().root, NULL ); .. that line is equivalent to root = q.front().root; >> If i am inserting things to queue by value{so the queue has the ownership} and then return a pointer to that queue {with root=merge( q.front().root, NULL );, when i leave the function scope (and the queue is destroyed) won't i have a problem?
the destructor of the leftistheap does not delete it's nodes (infact it does nothing). so if we merge the root of a leftistheap into another leftistheap and destroy the original leftistheap, the nodes will remain.

>> i tested your code with 15 elements(it compiled) ,but when i run it{and made a printout on the heap), i got a core dumped-segmentation fault error...
i have not been able to reproduce that error even with a million elements; with a simulated printout of the entire heap. this is an extract of the valgrind output.

>valgrind --leak-check=yes -v --show-reachable=yes ./project
...
==19458== Command line
==19458==    ./project
==19458== Startup, with flags:
==19458==    --leak-check=yes
==19458==    -v
==19458==    --show-reachable=yes
...
==19458== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==19458== malloc/free: in use at exit: 8192 bytes in 2 blocks.
==19458== malloc/free: 32802 allocs, 32800 frees, 54861840 bytes allocated.
==19458==
==19458== searching for pointers to 2 not-freed blocks.
==19458== checked 2456944 bytes.
==19458==
==19458== 8192 bytes in 2 blocks are still reachable in loss record 1 of 1
==19458==    at 0x3C03D183: malloc (in /usr/local/lib/valgrind/vgpreload_memcheck.so)
==19458==    by 0x3C20B099: __smakebuf (in …
vijayan121 1,152 Posting Virtuoso

>> Why the calls to new/delete harm the performance more than using by value passing?
this copy constructor does nothing more than the trivial bitwise copy that the compiler would have generated.

LeftistHeap::LeftistHeap(const LeftistHeap & rhs )
{
            root = NULL;
            *this = rhs;
}

as you have not declared an operator=, *this = rhs does a trivial bitwise assignment. (you can safely comment this constructor out; the inline bitwise copy that the compiler would generate would be faster than your out-of-line implementation and will do the same thing.) the same observation also holds for the do nothing destructor that you have.
since you are not using deep copy semantics, copying a LeftistHeap copies a pointer and an integer; destroying it would do nothing at all. new LeftistHeap on the other hand requires a call to operator new to allocate dynamic memory and delete LeftistHeap a call to operator delete to release the memory. these would typically require several dozen instructions to be executed. and you are doing this a very large number (several millions) of times.

>> ...so if i pop one, it will also be deleted so how can i ...
create a temporary copy (we have seen that this is inexpensive). and to avoid even this, try to use the object before popping it if possible. eg.

// note: added const to the input parameter to make it const-correct.
void LeftistHeap::initializeHeap( const std::vector<int>& vec )
{
      queue<LeftistHeap> q;
      for( int i=0; …
n.aggel commented: very helpfull post! +1
vijayan121 1,152 Posting Virtuoso

you are right (read i was wrong). the technique you have used is indeed O(N).
you could improve the performance by avoiding the calls to new/delete. using a queue having leftist_heap by value (not pointer to dynamically allocated objects) would make it even faster. note that the copy/assignment/destroy of (your implementation of) leftist_heap are trivial operations. it would still be O(N), but you would not have to call new/delete N times.

vijayan121 1,152 Posting Virtuoso

clearly the code (creating, merging, destroying a lot of heaps) you have is not very efficient. an alternative would be
1. write a function to add one element to an existing heap (push_heap).
2. to create a heap of N elements, start with an empty heap and iteratively call push_heap for each of the N elements.
this will do away with the need for creation/destruction of N heap objects.
i do not know the leftist heap data structure, but like in the standard heap (make_heap), there could be a faster algorithm to do this in linear time.

vijayan121 1,152 Posting Virtuoso

>> but why? i thaught that with this line the queue queue<LeftistHeap *> q; would be made responsible for desposing the elements....

the queue owns pointers to LeftistHeaps, not the LeftistHeaps themselves. so it would release what it owns, ie. the pointer, not the pointed object. the behaviour would have been different for a queue<LeftistHeap>.

>> why the size of leftistheap is just sizeof(pointer) + sizeof(int)??I also have three pointers in the leftistheap class...

the size of an object would include the size of its non-static member variables ( + a vptr if there are virtual functions + one vbaseptr for each virtual base class + any padding; however for yourLeftistHeap none of these apply). the only non-static member variables of a LeftistHeap are myNode *root; int emptyFlag; >> here is what i did... if the queue isn't responsible then i am, so i did something like this:
>> .....
>> doesn't work afterwards...as i would expect...
>> how can i deallocate something that i a not in control, because when i push the pointer in the queue i lose all control on that memory....

the queue will safely keep (a copy of) anything that you push into it. and give it back to you on demand.
do something like this instead.

void LeftistHeap::initializeHeap(std::vector<int> & vec)
{
   //prey to work!!!     
   queue<LeftistHeap *> q;


   for(int i=0; i<vec.size(); ++i)
   {
         q.push(new LeftistHeap(vec[i]) );
   }

   LeftistHeap *temp;

   while ( q.size()!=1)
     {
           temp = q.front(); …
n.aggel commented: great helper! +1
vijayan121 1,152 Posting Virtuoso

>> here is the only line where i allocate space in the program q.push(new LeftistHeap(vec[i]) ); the leak is because of that line; sizeof(LeftistHeap) == sizeof(pointer) + sizeof(int), adds up to 8 bytes on i386. the leak reported by valgrind is

80 bytes in 10 blocks are definitely lost in loss record 1 of 2
==1599== at 0x3C03D2F3: operator new(unsigned) (in /usr/local/lib/valgrind/vgpreload_memcheck.so)
==1599== by 0x804936E: LeftistHeap::initializeHeap(std::vector<int, std::allocator<int> >&) (LeftistHeap.cpp:206)

and in main.cpp we have enum { HOW_MANY_ELEMENTS = 10, TEST_ITERATIONS = 1, DISTRIBUITION_AREA=1024*1024 }; the blocks lost are the 10 LeftistHeap objects that you allocate using new and never delete.

change HOW_MANY_ELEMENTS to 1000 and valgrind will report 8000 bytes in 1000 blocks as definitely lost.
the dynamically allocated LeftistHeap objects are leaking; not the nodes

>> if i test this programm with valgrind, i don't get any errors.... which is weird...

valgrind automagically knows about memory that is still reachable. node_pool (has a static storage duration; still not destroyed at the point main returns) has references the the blocks it has allocated; so the memory is not *definitely* lost. in fact, the destructor of node_pool will free this memory.
you could verify this by using the valgrind switch --show-below-main=yes (continue stack traces below main)

vijayan121 1,152 Posting Virtuoso

check the function LeftistHeap::initializeHeap . valgrind is reporting 80 bytes in 10 unreachable blocks of memory allocated in this function. this is a leak.
the 2 reachable blocks are not memory allocated from your code (they are allocations by libc.so and will be released on program exit) and do not constitute a leak.

vijayan121 1,152 Posting Virtuoso

you would be better off using icc for processor-specific optimizations. even without processor-specific optimizations, icc generates better optimized code than vc++ 8; and it blows gcc away. http://www.intel.com/cd/software/products/asmo-na/eng/276615.htm

SpS commented: Right suggestion +4
vijayan121 1,152 Posting Virtuoso

> Or this to avoid break.
true, looks much neater
> You don't need the function pointer variable.
g++ (even very recent versions like 4.2) still does not have fully compliant "shadow headers" and can cause problems unless we tell the compiler explicitly that we intend using a pointer to a function. http://members.aon.at/hstraub/linux/newscache/porting-howto.html#sec-macros
this is a problem with the gnu libstdc++ . the code as dragon wrote (without the function pointer variable) works with most conforming implementations (microsoft, comeacu,icc).

vijayan121 1,152 Posting Virtuoso

dragon's algorithm does work. here is a version which a. uses isspace (handle all char sets) b. uses erase instead of extract substrings and concatenate (little more efficient). c. continues from the next char while repeatedly searching for whitespaces (again, little more efficient)

void remove_ws( vector<string>& vertex )
{
  int (*pfn_isspace)(int) = &isspace ;
  for( size_t i=0 ; i<vertex.size() ; ++i )
  {
      std::string& mystring = vertex[i] ;
      string::iterator where = mystring.begin() ;
      while(true)
      {
        where = find_if( where, mystring.end(), pfn_isspace ) ;
        if( where == mystring.end() ) break ;
        where = mystring.erase(where) ;
      }
  }
}
vijayan121 1,152 Posting Virtuoso

> i think im going to ask my IT teacher ... but he sucks
why don't you ask this person? http://www.research.att.com/~bs/bs_faq2.html#void-main

vijayan121 1,152 Posting Virtuoso

> i did what you suggested and i got::....
you have not defined node::node_pool.
see line 23 of the earlier post boost::pool<> node::node_pool( sizeof(node) ) ;

n.aggel commented: excellent poster! +1
vijayan121 1,152 Posting Virtuoso

if you are going to have only one object of your heap class at a time (ie. you do not create a second heap before destroying the existing one), you could just call boost::pool<>::purge_memory() in your destructor. or you could remove the destructor and call this from outside. or you could have one boost::pool<> per heap, and call boost::pool<>::purge_memory() on it in the destructor. the last option has technical merit, but would require some modification to the part of the code where you allocate/deallocate nodes.

vijayan121 1,152 Posting Virtuoso

> ...what do you mean by saying if the destructor of a node is a trivial one..here is my node:
the destructor of you node is trivial (ie. a destructor is deemed to be declared, but is not synthesized by the implementation).

> and if this is the only way to implement pool, i will have to write the part of the program that instantiates the heap....{everywhere i've use the new operator...}
the solution would be to overload operators new and delete for your node.
here is how you could do it using boost.pool

#include <boost/pool/pool.hpp>
#include <cassert>

struct node // has a trivial destructor
{
  int element ;
  node* left ;
  node* right ;
  int field ;
  static boost::pool<> node_pool ;
  static void* operator new( size_t sz )
  {
    assert( sz == sizeof(node) ) ;
    return node_pool.malloc() ;
  }
  static void operator delete( void* ptr )
  {
    assert( node_pool.is_from(ptr) ) ;
    node_pool.free(ptr) ;
  }
};

boost::pool<> node::node_pool( sizeof(node) ) ;

void allocate_lots_of_nodes_but_do_not_deallocate_them()
{
  // function allocates a large number of nodes
  for( int i = 0 ; i < 1023*1024*16 ; ++i )
  {
    node* pn = new node ;
    // do something with pn; perhaps insert into a tree etc.
    // don't bother to delete
  }
} 

int main()
{
  for( int i=0 ; i<8 ; ++i )
  {
    allocate_lots_of_nodes_but_do_not_deallocate_them() ;

    // frees every memory block. invalidates any pointers previously
    // returned by allocation functions
    node::node_pool.purge_memory() ;
  }
}
/**
>g++ -Wall -std=c++98 …
vijayan121 1,152 Posting Virtuoso

..so basically the problem is if i can free the memory without visiting every node....

since all the nodes are of the same size, you could use a pool allocation (also called "simple segregated storage"). see: http://www.boost.org/libs/pool/doc/concepts.html
boost.pool is a library you could use; it is very efficient. and you could free all chunks in a pool in one go. if the destructor of the node is a trivial one, you can bypass visiting all nodes. if not, you will have to traverse every node (with a little extra overhead: keep a pointer to the next allocated node with each node in the pool), this would be just a sequential, linear traversal.

vijayan121 1,152 Posting Virtuoso

since a heap is a *balanced* binary tree (it has the 'shape' property), you do not need nodes to implement it. we can store the heap in a compact manner in a (dynamically resizeable) array; this would be much more efficient. see: http://en.wikipedia.org/wiki/Binary_heap#Heap_implementation

vijayan121 1,152 Posting Virtuoso

are you trying to run your program from within the turbo c++ ide? in this case, the amount of heap memory that you have is very limited. the memory layout would be something like this (wwww < xxxx < yyyy < zzzz < a000) :

0000:0000 interrupt vector
0040:0000 dos low memory
wwww:0000 IDE code, data, heap, stack.
xxxx:0000 your program code.
yyyy:0000 your program data& stack.
zzzz:0000 your program heap.
A000:0000 end of heap (start of graphic memory).
"640 Kb is more than enough for anybody" - Bill Gates

with the changes ( char huge* I, delete[] I ), have you tried getting out of the ide and running the program from the shell (command.com)? even if it may not work from within the ide, it should work once you kick the ide out. you would then have more memory for your program.

this would take care of the code that you posted; you should have enough heap size for an array of 100KB. if you want array sizes of a few MB, you would need to use a dos extender (like DPMI) which allows access to the protected mode memory on your machine. i do not know if turbo C++ ships with a dos extender or would be able to use one if it is present. however, since you say "64K gives me 304 mm of movement of the machine whereas I need at least 2000 mm.", …

vijayan121 1,152 Posting Virtuoso
vijayan121 1,152 Posting Virtuoso

...compile and run the program on a more current compiler

runs without any problems on microsoft vc++ 8.0 and gcc 3.4.x (need to change headers iostream.h => iostream etc.)

Also I would value advice on which replacement compiler I should acquire. I would want an IDE and the machine computer interface board and real time limits me to using dos.

if you have to run under dos, this is reported to be a workable solution: http://www.delorie.com/djgpp/doc/ug/intro/what-is-djgpp.html & http://www.delorie.com/djgpp/v2faq/ it supports 32 bit addressing; so array sizes are not an issue if you have sufficient ram. see: http://www.delorie.com/djgpp/doc/ug/basics/32bit.html there is an ide for gjgpp: ttp://www.rhide.com/ djgpp is particularly popular among game programmers.

note: Salem's idea (sending a large array in smaller chunks of <64k) would be a simple and elegant solution; you should not rule it out without investigating the possibility.

Salem commented: Good idea - DJGPP +9
vijayan121 1,152 Posting Virtuoso

...I would be interested if you have successfully run the program with the pointer declared as huge...

no, i have not run the program. what i posted was based on (somewhat foggy) memory of the days when intel tortured programmers with segented addressing and memory models. i do not have the compiler; so i cannot test it.

the following suggestions are also based on guesswork:
a. verify that you are using a library which returns *huge* pointers for things like operator new / malloc. perhaps, the compiler ships with different libraries; one for each memory model. one way to check this is verify that for the huge pointer you try to use (of the form segment:offset) segment is non-zero and not equal to youir DS
b. try an malloc/free instead of a new/delete.
c. try using an array (declared as huge) with a static storage duration.

do you really have to use this compiler? (the real question is: do you really have to execute your code under the segmented addressing mode of intel?)

vijayan121 1,152 Posting Virtuoso

using far pointers you are still limited by 64K memory regions; its just that, that region can be outside your current CS or DS, and you can have many such regions. pointer arithmetic on far pointers do not modify the segment portion of the pointer, only its offset (modulo 64K arithmetic).

huge pointers are normalized every time they are modified; pointer arithmetic is *very* slow, but arrays of size >64k can be safely accessed. changing line 18 to

char huge* I ;

should work.

vijayan121 1,152 Posting Virtuoso

dynamic scoping is almost never used these days. with dynamic scoping, a variable reference is bound to the most recent instance of that variable on the call stack. for example:

#ifdef this_should_not_compile
void b() ; void c() ;
void a()
{
  int x = 24 ;
  int y = 32 ;
  int z = 0 ;
  b() ;
  assert( z == 132 ) ;
}

void b()
{
  int x = 100 ;
  c() ;
}

void c()
{
   z = x + y ; // would mean a()::z = b()::x + a()::y   
}

#endif // this_should_not_compile

// most C/C++ implementations use "context parameters" to simulate this
// for example, these are some Xlib functions:
//  
// int XDrawLine( Display* display, Drawable d, GC gc,
//                int x1, int y1, int x2, int y2 ) ;
// int XDrawArc( Display* display, Drawable d, GC gc,
//               unsigned int width, unsigned int height,
//               int angle1, int angle2 ) ;
//
// the parameters Display*, Drawable ang GC are the "context parameters"
// 
// with dynamic scoping, we could simply write
//
// int XDrawLine( int x1, int y1, int x2, int y2 ) ;
// int XDrawArc( unsigned int width, unsigned int height,
//               int angle1, int angle2 ) ;
//
// and the functions could pick up the caller's Display* display, 
// Drawable d, and GC gc from the stack frame

there are reasons why dynamic scoping has mostly disappeared from programming languages.
1. though it makes …

Salem commented: Ah yes, closures - a lot easier in some other languages. +9
vijayan121 1,152 Posting Virtuoso

the total store of c++ functions is fixed. these are the functions which were written when the code was compiled; there is simply no way to create new functions at run time. what differentiates function objects from functions is that they are objects (variables). in principle we can do everything with them that we can do with any other kind of variable. among other things, thay can hold state, they can be modified at run time and they can be created at run time. simply put, function objects give us a means to bundle a function call with implicit arguments to pass to that function. this allows us to build up complicated expressions using surprisingly simple syntax.

perhaps an example would help. we want to sort a sequence of integers; the sort criteria is a single digit of the integer at a position N (digit 0 being the least significant one). the value of N is known only at run time.
here is a version using c library qsort which requires a pointer to a comparison function (we avoid global variables for all the usual reasons - they encourage tight coupling, are a recipe for disaster in the presence of concurrency etc.):

#include <cstdlib>
#include <vector>
#include <iostream>
#include <boost/random.hpp>
#include <iterator>
#include <cassert>
using namespace std ;
using namespace boost ;

int compare_digit( int first, int second, int digit )
{
  int div = 1 ;
  for( int i=0 ; i<digit ; ++i ) div *= …
shouvik.d commented: You are the best to explain...Cheers to you +1
vijayan121 1,152 Posting Virtuoso
#include <fstream>
#include <string>
#include <vector>
#include <cassert>
using namespace std ;

int main()
{
  const char DELIM = '>' ;
  const char* const file_name = "whatever" ;
  ifstream file( file_name ) ; assert(file) ;
  vector<string> names, sequences ;
  string line ; 

  // skip lines till we get one starting with DELIM
  while( getline(file, line) ) 
    if( !line.empty() && line[0]==DELIM ) break ;

  names.push_back( line.substr(1) ) ;
  string charseq ;
  while( getline(file, line) )
  {
    if( !line.empty() && line[0] == DELIM )
    {
      sequences.push_back(charseq) ;
      charseq.clear() ;
      names.push_back( line.substr(1) ) ;
    }
    else
     charseq += line + '\n' ;
  }
  sequences.push_back(charseq) ;
}
iamthwee commented: short n sweet +11
vijayan121 1,152 Posting Virtuoso
enum { ROWS = 3, COLS = 5 };
   const int array[ROWS][COLS] = { /* ... */ } ;

   int max_in_row[ROWS] = { /* ... */ }, min_in_row[ROWS] = { /* ... */ },
         max_in_col[COLS] = { /* ... */ }, min_in_col[COLS] = {/* ... */ };

   for( int row=0 ; row<ROWS ; ++row )
     for( int col=0 ; col<COLS ; ++col )
     {
         // ...
     }
    // this is the only loop that iterates thru the elements (once).
   // at this point you should have arrays max_in_row,  min_in_row, 
   // max_in_col, min_in_col filled with the right values
vijayan121 1,152 Posting Virtuoso

now that you have solved it, can you make it more efficient? ie. find the max for each row and each col by making one single pass through the elements of the array.

vijayan121 1,152 Posting Virtuoso

How does main know that unit_test is going to test sorting ints? What if unit_test tests bubble_sort on five types instead of just one? I want to tell unit_test to use bubble_sort, but let unit_test pick the type.

for that we need to program with types at compile time rather than with variables at run time. this is called template metaprogramming and involves compile-time algorithms, sequences and metafunctions. i would suggest that you leave this problem for the present (until you have mastered things like partial specialization of templates). if you are curious, have a look at http://www.boost.org/libs/mpl/doc/tutorial/tutorial-metafunctions.html
for now; but come back later to tackle such problems.

vijayan121 1,152 Posting Virtuoso
/*
  sorting test

  Class based sorting
    by Kimberly Hamrick
*/
#include <algorithm> // for C+'s sort
#include <iostream>  // for C++ I/O
#include <stdlib.h>  // for random numbers

using namespace std;

template <typename Iterator>
void content_display( Iterator first, Iterator last ) {
  while ( first /*<*/ != last ) // more flexible
    cout<< *first++ <<" ";
  cout<<endl;
}

namespace hamrick {
  template <typename Iterator>
  void bubble_sort( Iterator first, /*const*/ Iterator last ) {
    Iterator current = first;

    // bubble up each element of the array
    while ( current /*<*/ != last ) {
      content_display( first, last );
      Iterator from = last ;
      bubble_up( /*last - 1*/ --from, current );
      ++current;
    }
  }

  template <typename Iterator>
  void bubble_up( Iterator from,  /*const*/ Iterator downto ) {
    // bubble up to the last sorted element
    while ( from /*>*/ != downto ) {
      Iterator temp = from ;
      if ( *from < *( /*from - 1*/ --temp) )
                swap( *from, */*(from - 1)*/temp );
      --from;
    }
  }
}

// Check that an array of T is sorted
template <typename T>
bool issorted( T array[], const int size ) {
  bool sorted = true;

  // it's sorted if the previous element is smaller
  // than the current element for all elements
  for ( int i = 1; i < size; i++ ) {
    if ( array[i - 1] > array[i] ) {
      sorted = false;
      break;
    }
  }

  return sorted;
}

template <typename FN, typename ITERATOR >
void call_function( FN func, ITERATOR begin, …
vijayan121 1,152 Posting Virtuoso

The first one works if I know what type T is. If I don't, it doesn't work. The second one doesn't work at all.

there was a typo in the second one (corrected now). if we also want to call the function with some arg, here is a modified version of the two functions.

#include <iostream>
#include <cstdlib>
#include <typeinfo>
using namespace std;

template < typename T > void template_function( T arg ) 
 { cout << "template_function< " << typeid(T).name() << " >\n" ; }

template< typename T >struct functor
{
  bool operator() ( const T& arg ) const 
  { return cout << "function_object\n" ; }
};

template < typename T > 
void function( void (*func)(T), T arg ) { func(arg) ; }

template <typename FN, typename T > 
void better_function( FN func, T arg ) { func(arg) ; }

int main()
{
  function( template_function< int >, 23 ) ;
  better_function( template_function< int >, 23 ) ;
  // function( strlen, "hello" ) ; // error
  better_function( strlen, "hello" ) ; // ok
  // function( functor< double >(), 5 ) ; // error
  better_function( functor< double >(), 5 ) ; // ok
}
vijayan121 1,152 Posting Virtuoso
template <typename T> void template_function( T arg ) ;

template <typename T>
void function( void (*func)(T) )
 { /* ... */ }

// this is better, would also accept compatible functions 
// and function objects
template <typename FN>
void better_function( FN arg )
 { /* ... */ }
vijayan121 1,152 Posting Virtuoso

I kind of figured what it does, but I haven't used enum yet, and I don't understand how numeric_limits works.

an unnamed enum as in enum { char_bits = numeric_limits<unsigned char>::digits }; in normal code is equivalent to const int char_bits = numeric_limits<unsigned char>::digits ; inside the body of a class, it is an just an easy way to define a constant (the value of which is known at compile time).
for numeric limits, see: http://www.dinkumware.com/manuals/?manual=compleat&page=limits2.html
ie: "http://www.dinkumware.com/manuals/?manual=compleat&page=limits2.html"

Endianness? What's that

see: http://en.wikipedia.org/wiki/Endianness

But it doesn't let me use _sep to divide the bytes. It just prints a long string of 1's and 0's.

we can do that quite easily. this is one way:

template <typename T>  class binary
  {
    public:
      explicit binary( const T value, const char *sep = " " )
         : _value( value ), _sep( sep ) {}

      friend ostream& operator<<( ostream& os, const binary& b )
      {
        bitset< sizeof(T)*char_bits > bs( b._value ) ;
        const string& str = bs.to_string() ;
        for( size_t i=0 ; i<sizeof(T) ; ++i )
           os << str.substr( i*char_bits, char_bits ) << b._sep ;
        return os ;
      }
    private:
      T  _value;
      string _sep;
  };

I don't understand what the example is doing. Why is that different from what I have?

in the above example, writing friend ostream& operator<<( ostream& os, [B]const[/B] binary& b ) implies that as far as this function is concerned, b can not be modified; neither b._value or b._sep. …

vijayan121 1,152 Posting Virtuoso

> it is probably wiser not to hold the seperator string (_sep) as a pointer; this might get us into trouble if a temporary was passed as the second constructor arg
>> But I thought because it's const that can't ever happen.

binary<int> to_binary( int n )
{
  char does_not_exist_once_fn_returns[] = "\n" ;
  binary<int> ret( n, sep ) ;
  return ret ;
}

when the function returns, lifetime of does_not_exist_once_fn_returns is over, but the returned object will hold the pointer. also, as in this example a non-const can be converted implicitly to a const.

> the hard coded assumption that CHAR_BITS==8 should be done away with
>> Isn't a byte always 8 bits? And a nybble is 4 bits?
in common usage, yes. but not as per the C standard. to quote it:
byte: The unit of storage in the execution environment large enough to hold any member of the basic character set of the execution environment. ... A byte is composed of a contiguous sequence of bits, the number of which is implementation-defined.
-- ISO/IEC 9899:1990(E) right on page 2
and the C++ standard is compatible with the C standard for the memory model of POD types.

>> you lost me with the enum and digits thing
C and cplusplus provide library headers (<limits.h> in C, <limits> in C++) which allow us to write correct code inspite of implementation differences. for a numeric type T, std::numeric_limits<T>::radix gives the radix and …

vijayan121 1,152 Posting Virtuoso

a. it is probably wiser not to hold the seperator string (_sep) as a pointer; this might get us into trouble if a temporary was passed as the second constructor arg
b. the hard coded assumption that CHAR_BITS==8 should be done away with
c. we could reuse the functionality available in std::bitset<>
d. and we can enable assignment by making the member variables non-const

#include <iostream> // for C++ I/O
#include <string>   // for C++ strings
#include <bitset>
#include <limits>
using namespace std;

namespace hamrick 
{
  enum { char_bits = numeric_limits<unsigned char>::digits };
  template <typename T>  class binary
  {
    public:
      explicit binary( const T value, const char *sep = " " )
         : _value( value ), _sep( sep ) {}

      friend ostream& operator<<( ostream& os, const binary& b )
      {
        typedef bitset< sizeof(T)*char_bits > bs ;
        return os << bs( b._value ) << b._sep ;
      }
    private:
      T  _value;
      string _sep;
  };

  template <>  class binary<string> 
  {
    public:
      explicit binary( const string& value, const char *sep = " " )
        : _value( value ), _sep( sep ) {}

    friend ostream& operator<<( ostream& os, const binary& b )
    {
      for( size_t i=0 ; i < b._value.size() ; ++i )
        os << bitset< char_bits >( b._value[i] ) << b._sep ;
      return os ;
    }
    private:
      string _value;
      string _sep;
  };
}

int main()
{
  cout<< hamrick::binary<int>( 1234 ) <<endl;
  cout<< hamrick::binary<string>( "ABCD" ) <<endl;

  for ( int a = 0; a < 256; a++ )
    cout<< hamrick::binary<char>( a …
vijayan121 1,152 Posting Virtuoso

That makes sense. But even when I disable intrinsics, the result is the same. Is Visual C++ really using a different function than the one in the CRT source folder?

it appears so - the disassembly code i posted is with intrinsics disabled. perhaps there are different versions of sources for the debug version of the library and the release version. i do not have the CRT source for visual studio with me (i tested it on vc++ express); you could look into the CRT source tree for a directory containing assembly code.

vijayan121 1,152 Posting Virtuoso

without intrinsics, the code generated for hamrick::strlen is:

;    COMDAT ?strlen@hamrick@@YAIPBD@Z
_TEXT    SEGMENT
_str$ = 8                        ; size = 4
?strlen@hamrick@@YAIPBD@Z PROC                ; hamrick::strlen, COMDAT

; 49   :     // treat a null pointer as an empty string
; 50   :     size_t len = 0;
; 51   : 
; 52   :     if ( str != 0 ) {

    mov    ecx, DWORD PTR _str$[esp-4]
    xor    eax, eax
    test    ecx, ecx
    je    SHORT $LN1@strlen

; 53   :       // find the end and count each character
; 54   :       while ( *str != '\0' ) {

    cmp    BYTE PTR [ecx], al
    je    SHORT $LN1@strlen
    npad    2
$LL2@strlen:

; 55   :         ++len;
; 56   :         ++str;

    add    ecx, 1
    add    eax, 1
    cmp    BYTE PTR [ecx], 0
    jne    SHORT $LL2@strlen
$LN1@strlen:

; 57   :       }
; 58   :     }
; 59   : 
; 60   :     return len;
; 61   :   }

    ret    0
?strlen@hamrick@@YAIPBD@Z ENDP                ; hamrick::strlen
_TEXT    ENDS

for hamrick::xstrlen, it is

PUBLIC    ?xstrlen@hamrick@@YAIPBD@Z            ; hamrick::xstrlen
; Function compile flags: /Ogtpy
;    COMDAT ?xstrlen@hamrick@@YAIPBD@Z
_TEXT    SEGMENT
_str$ = 8                        ; size = 4
?xstrlen@hamrick@@YAIPBD@Z PROC                ; hamrick::xstrlen, COMDAT

; 65   :     const char *eos = str;

    mov    ecx, DWORD PTR _str$[esp-4]
    mov    eax, ecx
$LL2@xstrlen:

; 66   :     while( *eos++ ) ;

    mov    dl, BYTE PTR [eax]
    add    eax, 1
    test    dl, dl
    jne    SHORT $LL2@xstrlen

; 67   :     return( eos - str - 1 );

    sub    eax, ecx
    sub    eax, 1

; 68   :   }

    ret    0
?xstrlen@hamrick@@YAIPBD@Z ENDP                ; hamrick::xstrlen …
vijayan121 1,152 Posting Virtuoso

> the assembly output doesn't show me the code generated for C++'s strlen(), just my strlen() and xstrlen().

the microsoft C++ compiler recognizes and directly inserts optimized inline code for several functions (including strlen). functions like strlen in the Standard C library are available in both intrinsic and non-intrinsic forms. we can control the use of intrinsics by inserting #pragma intrinsic statements into the source code or using the -Oi compiler switch.

vijayan121 1,152 Posting Virtuoso

if the enums have consecutive integral values (as in this case), we can increment by adding one to the value.

#include <iostream>
int main()
{
  enum level { FRESHMAN=0, SOPHMORE=1, JUNIOR=2, SENIOR=3 } ;
  const char* const literal_level[] = 
                            { "FRESHMAN", "SOPHMORE", "JUNIOR", "SENIOR" } ;
  for( level lev = FRESHMAN ; lev <= SENIOR ; lev = level(lev+1) )
      std::cout << literal_level[ lev ] << '\n' ;
}
vijayan121 1,152 Posting Virtuoso

the server will bind to an address and start listening on it. the client socket is usually dynamically bound and tries to connect to the socket at the address the server has bound. so the port the client tries to connect to should be the same as the one the server used in the call to bind.
1234 is not an ideal choice for the port though. see http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers

will this connection be established? can't say. the port may already be in use (for 1234, this is likely in windows), the connection may be blocked/dropped by a firewall etc.

vijayan121 1,152 Posting Virtuoso
const char* const months = "*ABCDEFGHIJKL" ;

inline char month_to_code( int m ) 
{ 
  assert( m>0 && m<13 ) ;
  return months[ m ] ; 
}

inline int code_to_month( char c ) 
{ 
  const char* p = strchr( months, toupper(c) ) ; 
  assert( p!=0 && p!=months ) ; 
  return p - months ; 
}

// etc

after sorting out issues that Ancient Dragon pointed out

vijayan121 1,152 Posting Virtuoso

after exiting from main, the following actions are performed:
a. call destructors of objects with static storage
b. call atexit functions
c. deinit the C runtime library
during this, it was detected that some dynamically allocated memory block is invalid. this can occur due to a variety of reasons; but the fragment pHead->nBlockUse usually indicates that you are trying to free memory that has already benn freed. (it is also possible that a block header was corrupted by writing beyond the bounds of allocated memory in an adjecent block). if there is no instance of any such error in your own code, it would have been caused by something incorrect in a library that you are using.

vijayan121 1,152 Posting Virtuoso
#include <vector>
#include <boost/tokenizer.hpp>
#include <string>
#include <vector>
#include <iostream>
using namespace std;
using namespace boost;

int main()
{
  string str = "The boost tokenizer library provides a flexible "
                       "and easy to use way to break of a string or other "
                       "character sequence into a series of tokens.\n"
                       "Here is a simple example that will break up a "
                       "paragraph into words.\n";
  tokenizer<> toker( str );
  vector<string> words( toker.begin(), toker.end() ) ;
  cout << "there are " << words.size() << " words\n" ;
  cout << "words[6]: " << words[6] << '\n' ;
}
vijayan121 1,152 Posting Virtuoso

members or base class sub-objects cannot be initialized inside the body of the constructor; they can only be assigned to. initialization is always before the body of the constructor executes. if not initialized expliciltly using colon initialization, the implementation will provide default initialization if available. for any member which does not have default initialization (constants and references are examples of these), an explicit initialization would have to be provided.

struct A
{
  A() 
     // error 1: must_be_initialized must be initialized
  {
    must_be_initialized = 0 ; // error 2: constant can't be assigned to
  }
  const int must_be_initialized ;
};
vijayan121 1,152 Posting Virtuoso

Also bear in mind that some old versions of turbo c++ and nearly all versions of Visual Studio do not adhere to the standard

the c++ front-end from Edison Design Group is the only implementation to support the complete C++ standard ISO/IEC 14882:2003. see: http://www.edg.com/index.php?location=c_lang
a good test for compiler conformance is to look at the implementation of the Dinkumware C++ library
(a completely conforming implementation of the standard C++ library ISO/IEC 14882:1998, as corrected through 2003.). as per dinkumware,
"As a general rule, you can expect reasonably complete library functionality when using Microsoft Visual C++ compilers from V7.1 onward, GCC compilers from V3.0 onward, and all compilers using the EDG front end. Only EDG compilers offer complete Standard C and C++ conformance (when used with Dinkumware libraries), and only EDG V3.5 and later supports fixed-point arithmetic (TR18037)."
http://www.dinkumware.com/manuals/
current versions of the microsoft c++ compiler use libraries from dinkumware; gcc libstdc++ implementations from version 3.4.0 are also fairly conformant. the recently released Turbo C++ 2006 (sep 2006) includes the Dinkumware C++ libraries and my guess is that the conformance would be reasonable.

vijayan121 1,152 Posting Virtuoso
if( std::find( alist.begin(), alist.end(), x ) != alist.end() )
{ /* do this */ }
vijayan121 1,152 Posting Virtuoso
struct A
{
   std::string str ;
   explicit A( const char* cstr ) ;
   explicit A( const std::string& s ) ;
};

A::A( const char* cstr ) : str(cstr) {}
A::A( const std::string& s ) { str = s ; }

the constructor using initializer syntax is more efficient; it directly constructs the string from a const char*. the one using assignment first constructs a string using its default constructor and then assigns one string to another.
there would be no difference if the default initialization is trivial (for example an int member); initializer syntax is required if there is no default initialization available(reference or const members, user defined type with no or inaccessible default constructors).

vijayan121 1,152 Posting Virtuoso
vijayan121 1,152 Posting Virtuoso
class D
{
   // ...
   D operator- ( const D& d2 ) const;
   // ...
};
D D::operator- ( const D& d2 ) const
{
  // ...

would also make your code const-correct.

vijayan121 1,152 Posting Virtuoso

for standard C++ (ISO/IEC 1998,2003), the project type you would use is one of Win32 Console Application / Win32 library / General MakeFile Project. if you are new to Visual Studio 2005, start with a Win32 Console Application project. and in the project settings, disable microsoft language extensions. ( either /Za compiler switch or from the IDE, Menu -> Project -> Properties -> Configuration Properties -> C/C++ -> Language -> Disable Language Extentions = True )