Tuesday, January 19, 2010

Clear input stream in C++ - fflush(stdin) equivalent in C

You can't use flush to clear the input stream in C++, it's equivilent to using fflush(stdin) for C. Sometimes it works, sometimes it doesn't, but all of the time it's a bad idea.


cin >> flush;


To clear the input stream in C++ use cin.ignore() everytime you think the input stream may still have data in it.


cout<<"Enter your name"<cin.getline(name, 50, '\n'); //ignore not needed, getline does it
cout<<"Enter your age"<cin>>age; cin.ignore(); //clear the newline from the stream
cout>>"Enter your height"<cin>>height; //this will work now

Thursday, January 7, 2010

Compilation and linking issues for C++ template classes

The common practice in C++ is to write the class definition in a header file(.h file) and to write the class implementation in a source file(.cpp file). This reason behind this is to keep the interface separate from the implementation. This source file is compiled separately. When we want to use the class in another source file say test_stack.cpp, we need to include the header file in test_stack.cpp. We then need to compile this test_stack.cpp and link the object files to make the executable.

But if we want to follow the same practice for a template class, some linking issues arise.

Linking Issue:

Here goes the source files and header file.



//stack.h

#ifndef STACK_H
#define STACK_H

template class Stack {
T *v;
int max_size;
int top;
public:
class Underflow {};
class Overflow {};

Stack(int s);
~Stack();

void push(T);
T pop();
};

class Bad_size {};
class Bad_pop {};

#endif

//stack.cpp

#include "stack.h"

template Stack::Stack(int s) {
top = 0;
if (10000 < s) throw Bad_size();
max_size = s;
v = new T[s];
}

template Stack::~Stack() {
delete [] v;
}

template void Stack::push(T c) {
if (top == max_size) throw Overflow();
v[top++] = c;
}

template T Stack::pop() {
if (top == 0) throw Underflow();
return v[--top];
}

// test_stack.cpp
#include "stack.h"
#include
#include
#include

Stack sc(10);
Stack< std::complex > scplx(10);
Stack< std::list > sli(10);

void f() {
sc.push('a');
sc.push('b');
sc.push('c');
if (sc.pop() != 'c') throw Bad_pop();

scplx.push(std::complex(1, 2));
scplx.push(std::complex(2, 3));
scplx.push(std::complex(3, 4));

if (scplx.pop() != std::complex(3, 4)) throw Bad_pop();

std::cout << "stack of characters, sc: " << sc.pop() << ' ' << sc.pop() << '\n';
std::cout << "stack of complex numbers, scplx: " << scplx.pop() << ' ' << scplx.pop() << '\n';
}

int main() {
f();
return 0;
}



When you try to link the object files created from compiling source files, some linking problems arise:



$ g++ -c stack.cpp
$ g++ -c test_stack.cpp
$ g++ -o test_stack stack.o test_stack.o
test_stack.o: In function `__static_initialization_and_destruction_0(int, int)':
test_stack.cpp:(.text+0x56): undefined reference to `Stack::Stack(int)'
test_stack.cpp:(.text+0x5b): undefined reference to `Stack::~Stack()'
test_stack.cpp:(.text+0x87): undefined reference to `Stack >::Stack(int)'
test_stack.cpp:(.text+0x8c): undefined reference to `Stack >::~Stack()'
test_stack.cpp:(.text+0xb8): undefined reference to `Stack >
-----
------
------
collect2: ld returned 1 exit status



Reason

When the compiler encounters a declaration of a Stack object of some specific type, e.g., int , it must have access to the template implementation source. Otherwise, it will have no idea how to construct the Stack member functions. And, if you have put the implementation in a source (stack.cpp) file the compiler will not be able to find it when it is trying to compile the client source file test_stack.cpp. And, includeing the header file (stack.h) will not be sufficient at that time. That only tells the compiler how to allocate for the object data and how to build the calls to the member functions, not how to build the member functions. And again, the compiler won't complain. It will assume that these functions are provided elsewhere, and leave it to the linker to find them. So, when it's time to link, you will get "unresolved references" to any of the class member functions that are not defined "inline" in the class definition.

Solution

There are different methods to solve this problem. You can select from any of the methods below depending on which is suitable for your application design:

Way 1

You can create an object of a template class in the same source file where it is implemented
(stack.cpp). So, there is no need to link the object creation code with its actual implementation in some other file. This will cause the compiler to compile these particular types so the associated class member functions will be available at link time. Here goes the changes in stack.cpp:




#include "stack.h"

template Stack::Stack(int s) {
top = 0;
if (10000 < s) throw Bad_size();
max_size = s;
v = new T[s];
}

template Stack::~Stack() {
delete [] v;
}

template void Stack::push(T c) {
if (top == max_size) throw Overflow();
v[top++] = c;
}

template T Stack::pop() {
if (top == 0) throw Underflow();
return v[--top];
}

// No need to call this temporaryFunction() function,
// it's just to avoid link error.
void temporaryFunction ()
{
// you need to use those functions here which will be called from test_stack.cpp
Stack sc(10);
sc.push('a');
sc.pop();
}



The temporary function in "stack.cpp" will solve the link error. No need to call this function because it's global.

Way 2

You can #include the source file that implements your template class stack.cpp in your test_stack.cpp source file



#include "stack.h"
#include "stack.cpp"
#include
#include
#include

Stack sc(10);
Stack< std::complex > scplx(10);
Stack< std::list > sli(10);

void f() {
sc.push('a');
sc.push('b');
sc.push('c');
if (sc.pop() != 'c') throw Bad_pop();

scplx.push(std::complex(1, 2));
scplx.push(std::complex(2, 3));
scplx.push(std::complex(3, 4));

if (scplx.pop() != std::complex(3, 4)) throw Bad_pop();

std::cout << "stack of characters, sc: " << sc.pop() << ' ' << sc.pop() << '\n';
std::cout << "stack of complex numbers, scplx: " << scplx.pop() << ' ' << scplx.pop() << '\n';
}

int main() {
f();
return 0;
}



In this case you dont need to compile stack.cpp. You need to compile and link only test_stack.cpp

Way 3

You can #include the source file that implements your template class (stack.cpp) in your header file that defines the template class (stack.h).



#ifndef STACK_H
#define STACK_H

template class Stack {
T *v;
int max_size;
int top;
public:
class Underflow {};
class Overflow {};

Stack(int s);
~Stack();

void push(T);
T pop();
};

class Bad_size {};
class Bad_pop {};

#include "stack.cpp"

#endif



In this case you dont need to compile stack.cpp. You need to compile and link only test_stack.cpp

Way 4

You need to make the class functions inline i.e. implement those inside stack.h and remove stack.cpp. In this case you need to compile and link only test_stack.cpp

Tuesday, September 1, 2009

PEAR Installation Problem: unsupported protocal

I was trying to install PHPUnit, a member of XUnit family of testing frameworks. While running this command:


pear install phpunit/PHPUnit


I got this error:


pear.phpunit.de is using a unsupported protocal – This should never happen. install failed


What I found through investigation is that PEAR installations on PHP 5.2.9 and 5.2.10 seem to be corrupted and I am using PHP 5.2.9. This problem comes from corrupted channel files. The solution is: Go into your PEAR php directory and backup .channels directory.


cd `pear config-get php_dir`
mv .channels .channels-broken
pear update-channels


This means you lost all your channels except for the default ones (pear, pecl, doc and __uri) – but at least you do not have to re-install PEAR :)

Sunday, August 23, 2009

Installing Apache httpd-2.2.11 from source in Ubuntu 9.04

I was trying to install httpd-2.2.11 from source in Ubuntu 9.04.When I tried to execute the first command which is 'configure' with some options like this:


$ ./configure --with-included-apr --enable-cache --enable-mem-cache --enable-ssl --enable-rewrite
--enable-so --enable-deflate


I got this error:


checking whether to enable mod_deflate... configure: error: mod_deflate has been requested but can not be built due to
prerequisite failures


After doing some investigation, I found that zlib1g-dev was not installed. So I installed this using this command:


$ sudo apt-get install zlib1g-dev


Then I tried to install apache again. When I ran configure again, I got this error:


no OpenSSL headers found
checking for SSL-C version... checking sslc.h usability... no
checking sslc.h presence... no
checking for sslc.h... no
no SSL-C headers found
configure: error: ...No recognized SSL/TLS toolkit detected


That means either openssl or libssl-dev was not installed. I was sure that openssl was installed. So I installed libssl-dev using this command:


$ sudo apt-get install libssl-dev


Then I tried to install httpd again and it was successfully installed. :)

Friday, July 24, 2009

Installing the Connector/J in Windows XP with JDK 1.6.0_14

I am writing this post only to note down some quick things that may not be remembered at all times, specially when it is needed :)

You can follow these steps:
  1. Extract the zip file mysql-connector-java-5.1.8.zip in any place as you wish.
  2. Copy file 'mysql-connector-java-3.1.12-bin.jar' from the extracted folder into \jre\lib\ext folder. jdk1.5\jre\lib\ext folder which on my system happens to be 'C:\Program Files\Java\jdk1.6.0_14\jre\lib\ext folder. jdk1.5\jre\lib\ext'.
  3. Go to control Panel->Advance->Environment Variable->System Variable.
  4. The next step depends on your system variable:
  5. IF YOU HAVE CLASSPATH:
  6. Click once at Classpath and then click edit.
  7. At the end of the Variable Value, simply put ';\jre\lib\ext\mysql-connector-java-5.1.8-bin.jar' (Without the single quotes ;) which on my system happens to be ';C:\Program Files\Java\jdk1.6.0_14\jre\lib\ext\mysql-connector-java-5.1.8-bin.jar'.
  8. Click OK.
  9. IF YOU DO NOT HAVE CLASSPATH:
  10. Click on New.
  11. Put 'CLASSPATH' at Variable name, and '.;\jre\lib\ext\mysql-connector-java-5.1.8-bin.jar' at Variable Value.
  12. Click OK

Monday, July 20, 2009

Writing code in blogspot

I am a new and infrequent blogger. So, while writing some php code in one of my post, I was looking for a way to put those code so that code indentation and other aspects don't get lost. After some googling, I found this post as a useful one for that purpose: http://blog.mijalko.com/2008/10/writing-code-in-blogspot.html

A simple solution and off-course a KISS one :)

Friday, July 17, 2009

mysql-5.1.36 in Ubuntu 9.04: FATAL ERROR: Could not find mysqld

I was building mysql-5.1.36 in Ubuntu 9.04 - the Jaunty Jackalope. I was following the instructions given in INSTALL-SOURCE provided with the package. I was trying to create the MySQL data directory and initialize the grant tables by running this command:

$ sudo bin/mysql_install_db --user=mysql

I got this error:

FATAL ERROR: Could not find mysqld

The following directories were searched:

/usr/libexec
/usr/sbin
/usr/bin

If you compiled from source, you need to run 'make install' to copy the software into the correct location ready for operation.

If you are using a binary release, you must either be at the top of the level of the extracted archivem or pass the --basedir option pointing to that location.

After a bit googling and investigation, I found that this package mysql-common was already installed with
Ubuntu 9.04 and there is a file my.cnf in /etc/mysql and db initialization was using this file instead of the one I copied to /etc with this command while following the INSTALL-SOURCE file:

$ sudo cp support-files/my-medium.cnf /etc/my.cnf

So the quick fix was to replace /etc/mysql/my.cnf with /etc/my.cnf that I copied earlier. I did these:

$ sudo mv /etc/mysql/my.cnf /etc/mysql/my_backup.cnf
$ sudo cp /etc/my.cnf /etc/mysql/