Showing posts with label C. Show all posts
Showing posts with label C. Show all posts

Tuesday, January 7, 2020

Declaring a class type member variable in OO way

Wonder what is wrong with my code? Am I forgotten how could I declare and initialize static member of a class?
class Configuration
{
private:
   static b2Vec2 gravity(0.0f, -0.05f);
}
Should be. I am getting this error really scratching my head hard.
/home/kokhoe/workspacec/OpenGL2/header/Configuration.h:47:24: error: expected identifier before numeric constant
   47 |  static b2Vec2 gravity(0.0f, -0.05f);
      |                        ^~~~
No. Not really. It has nothing to do with static or not. Just that I have forgotten the way to declare a class type member variable in object oriented way. The correct way of declaring a class type should be like this:
class Configuration
{
private:
   static b2Vec2 gravity = b2Vec2(0.0f, -0.05f);
}
Somehow b2Vec2 is a struct not class. This has cause the compilation error:
/home/kokhoe/workspacec/OpenGL2/header/Configuration.h:44:16: error: in-class initialization of static data member ‘b2Vec2 Configuration::gravity’ of non-literal type
   44 |  static b2Vec2 gravity = b2Vec2(0.0f, -0.05f);
      |                ^~~~~~~
Since b2Vec2 is a struct, I remove the static keyword and it compile successfully.

Monday, February 15, 2016

Does Flyweigh pattern really help in memory management?

In a game architecture design, memory allocator is one of the core modules sit in the game system. I’m so wondering how could I implement this module and why do I need this? After reading many articles from the experts, understand that this is a crucial part of game performance when there are thousands of game objects being spawned at a time. Due to the slow performance of the new/delete operator, it is advisable to implement a very own or game specific memory allocator. But how could I do it?

Forget about those big games adopting very advance features of memory allocator. I should focus on my game since my game is categorized as a casual game. So the most basic need for me would be:
  1. Able to allocate from OS and release memory back to the OS.
  2. The memory pool should be expandable and return the memory back into the pool.
  3. The memory pool should not release the memory back to OS until the game exit.
For this purpose, I’m borrowing the idea of Flyweigh pattern, the idea of this pattern is to minimize the memory usage by sharing as much data as possible with other similar objects. First thing first, I define a default pool size of 10 whenever a new memory pool was created:
template <typename T>
class GameObjectPool
{
private:
 static const int POOL_SIZE = 10;

 T *freshPiece; 
}
Notice the use of template for this class, it is to allow the game to be able to allocate different kinds of game object (eg. particle, sprite) in the pool. freshPiece will be responsible for holding the available memory chunk for the game object. When the pool is first constructed, freshPiece was empty. There isn't any game object hold by freshPiece. Thus, the pool will first acquire some memory from the OS. This was done in the constructor:
template <typename T>
class GameObjectPool
{
public:
 GameObjectPool () {
  fillUpMemory();
 }
 ...
private:
 void fillUpMemory() {
  T *curObj = new T();
  freshPiece = curObj;

  for (int i = 0; i < POOL_SIZE - 1; i++) {
   curObj->setNext(new T());
   curObj = curObj->getNext();
  }

  curObj->setNext(nullptr);
 }

}
Once the game was finished, the memory is released back to the OS:
template <typename T>
class GameObjectPool
{
public:
 ~GameObjectPool() { 
  Particle *curObj = freshPiece;

  if (freshPiece != nullptr) {
   for (; curObj; curObj = freshPiece) {
    freshPiece = freshPiece->getNext();
    delete curObj;
   }
  }
 }
}
During the game runtime, the game object will acquire the memory from the pool instead of using the new keyword:
template <typename T>
class GameObjectPool
{
public:
 inline T *create() {
  if (freshPiece == nullptr)
   fillUpMemory();

  T *curObj = freshPiece;
  freshPiece = freshPiece->getNext();

  return curObj;
 }

}
Once the game object has done his job, the memory will release back to the pool. Same thing as acquiring the memory, no delete keyword is used:
template <typename T>
class GameObjectPool
{
public:
 inline void release(T* obj) {
  obj->setNext(freshPiece);
  freshPiece = obj;
 }
}
Notice the POOL_SIZE I pre-code it to 10, this is due to my laziness. I let the pool automatically allocate the predefined pool size if it exceeds the available pool size. May be in the future, I will need a more elegant way to adjust the pool size as shown below:
template <typename T>
class GameObjectPool
{
public:
GameObjectPool() {
  fillUpMemory();
 }

 GameObjectPool(int poolSize) : mPoolSize(poolSize) {
  fillUpMemory();
 }

...

private:
 void expandPoolSize() {
  T *curObj = new T();
  particleHead = curObj;

  for (int i = 0; i < mPoolSize - 1; i++) {
   curObj->setNext(new T());
   curObj = curObj->getNext();
  }

  curObj->setNext(nullptr);
 }

private:
 int mPoolSize = 10;

 T *freshPiece; 
}
Well, this is my very first version that meets the most basic fundamental of my game.

Sunday, November 29, 2015

Accessing std::set container by index position

You like it or not? Accessing an element of a set container by index position is different from the vector container as it doesn't support operator[]. There is a weird way of doing this. Before I got to aware this shortcut, I was doing it in this manner:
   set<int> s;
   set<int>::iterator is;
   for (is = s.begin(); is != s.end(); is++)
      ...
This will loop until my desire string is found. Unlike vector, I can not do something like this: s[0]. The compiler will never allow this shit to proceed further. Sigh! If it is not supported, then I have to find the other way. As of my finding, this seems to be workable:
   ...

   str = (*std::next(s.begin(),4)).c_str();
   ...
With this, I'll be able to access the 4th elements of s. I'm sure the 4th element is not null, otherwise that code will cause my shit to blow up during runtime.

Thursday, November 26, 2015

Trick to iterate queue in C++

Oh shit! Iterator was not part of the queue interface, then how could I iterate the content of the queue?

While I was unit testing my code, I want to check whether the queue does contain any search string found in the queue. Thus, I have a QueuePath which storing some text and then iterate the queue with following way, it failed.
typedef queue<wstring> QueuePath;
QueuePath::iterator it;
for( it=list.begin(); it != list.end(); it++ ) {
   …
}
This will hit compilation error because an iterator isn’t a member of the queue, thus a better resolution would be to use deque. Since my earlier design was started with queue, I didn’t really want to change it for now. While searching for a solution, I had discovered the new trick in ideone.com which is to iterate the queue. This trick is a work around for the queue to support the iterator interface.
#include <deque>
#include <queue>

using namespace std;

template< typename T, typename Container=std::deque<T> >
class MyQueue : public queue<T,Container>
{
public:
	typedef typename Container::iterator iterator;

	iterator begin() { return this->c.begin(); }
	iterator end() { return this->c.end(); }
};
int _tmain(int argc, _TCHAR* argv[])
{
	MyQueue<int> q;
	for (int i = 0; i < 10; i++)
		q.push(i);

	for (auto it = q.begin(); it != q.end(); it++)
		cout << *it << endl;

	return 0;
}
Although this workaround is damn real cool, but I was so reluctant to change my code. Anyway, think about it, do I really need this just for the unit testing? Basically, I could have something like below to get my job accomplished since I’m working on the unit test.
while( !list.empty() ) {
        …
        list.pop();
}
Remember my objective? The objective of this unit test is to make sure that the content in the queue was correct.

Sunday, November 22, 2015

My new reinforcement on C++ unit test

A few weeks ago, while I was working out on CppUnit in unit testing and I found out that it wouldn’t work as I doesn’t have MFC framework install in my Windows. Now I had discovered Boost.Test for this critical mission. The first contact on the new discovery, I have following code ready to charge:
#define BOOST_TEST_MODULE Hello
#include <boost/test/unit_test.hpp>

int add(int i, int j)
{
    return i+j;
}

BOOST_AUTO_TEST_CASE(Case1)
{
    BOOST_CHECK(add(2,2) == 4);
}
Interestingly, the test doesn’t get executed, but the main entry point of the program, int main(int argc, char* argv[]) was called. I spent the whole day reading through the documentation still has not got any clue on it. Until I remove the main entry point, and something were shown on the screen:
Running 1 test case...

*** No errors detected
Press <return> to close this window...
This is pretty exciting as I got a first unit test up and running. Thinking out from the plan, I need a separate project just for the unit test.

Thursday, September 24, 2015

Initialization list doesn't work for virtual constructor?

A virtual base class is always initialized before other derive class. This is a known behavior. I'm aware of it. But what's surprising me is that when I have an intermediate class pass parameter to the virtual base class constructor in their member initialization list, these initialization list will be ignored. The following piece could prove this statement.
class Parent {
public:
 Parent() : param(0) {
  cout << "Parent constructor" << endl;
 }

 Parent(int param) : param(param){
  cout << "Parent constructor(param)" << endl;
 }

 int getParam() { return param; }

private:
 int param;
};

class Base : virtual public Parent {
public:
 Base() : Parent(5373) {
  cout << "Base constructor" << endl;
 }
};

class Xtends : public Base {
public:
 Xtends() {
  cout << "Xtends constructor" << endl;
 }
};
When I execute the following piece, the param value would be 0:
   Xtends x;
   cout << "param: " << x.getParam() << endl;
Notice the Base class is an intermediate class. When I pass in the value of 5373 into Parent( int ) constructor, it simply ignores it. Next the Base class is no longer an intermediate class. Now when I execute the following code, the value of 5373 would be seen:
   Base b;
   cout << "param: " << b.getParam() << endl;

Friday, August 21, 2015

log4cpp::Category::xxx() do accept c_str()

Just got to know that in order to log a value of boost::filesystem::path with log4cpp, it is just as simple as follows:
   Category *pRoot = NULL;
   PropertyConfigurator::configure("log4c.properties");
   pRoot = &(Category::getRoot());

   path targetPath("./the_path");
   pRoot->info("%s", targetPath.c_str());
Assuming I have the following content in log4c.properties:
   log4cpp.rootCategory=DEBUG, rootAppender

   log4cpp.appender.rootAppender=ConsoleAppender
   log4cpp.appender.rootAppender.layout=PatternLayout
   log4cpp.appender.rootAppender.layout.ConversionPattern=%d [%p] %m%n

   ...
But before I got to know this, I heard there are people mention that the conversion from c_str() to const char* would not be straightforward. And it would require wcstombs() to do the conversion, thus I come out this:
   ...

   char pathName[50];
   memset(pathName, '\0', sizeof(pathName));
   wcstombs(pathName, targetPath.wstring().c_str(), sizeof(targetPath.native().length()));
   ...
Is this what they mean? Or I misunderstood something? No worry, log4cpp::Category::xxx() do accept c_str(). 

Tuesday, February 10, 2015

Finding index of Nth occurrence of a string

Recently I was working on a task that require me to find the Nth occurrence of a string. In other words, this function should return the position index of Nth occurrence. For example, the 2nd occurrence of o in a string hello world will locate at 7. Thus, I have following code created for this:
int searchNth(const char* work, const char* find, const int nth) {

 int work_len = strlen(work);
 int find_len = strlen(find);
 int match_count = 0;
 int match_index_pos = -1;
 int occurrence = -1;

 for (int i = 0; i < work_len; i++) {

  if (work[i] == find[match_count]) {
   match_count++;

   if (match_count == 1) {
    match_index_pos = i;
   }
  }
  else if (match_count > 0 && work[i] != find[match_count]) {
   match_count = 0;
   match_index_pos = -1;
  }

  if (find_len == match_count) {
   occurrence++;
  }

  if (nth == occurrence) {
   return match_index_pos;
  }
 }

 return -1;
}
Sample of execution:

searchNth("hello world", "o", 1); // output: 7
searchNth("hello world", "o", 2); // output: -1
searchNth("hello world", "o ", 0); // output: 4

Well, I'm pretty proud of myself because I have created such a nice piece of code that could return the nth occurrence of a string. (Not really!) Someone has better solution than mine. I just found the answer in this thread.
size_t find_Nth(
    const std::string & str ,   // where to work
    unsigned            N ,     // N'th ocurrence
    const std::string & find    // what to 'find'
) {
    if ( 0==N ) { return std::string::npos; }
    size_t pos,from=0;
    unsigned i=0;
    while ( i<N ) {
        pos=str.find(find,from);
        if ( std::string::npos == pos ) { break; }
        from = pos + 1; // from = pos + find.size();
        ++i;
    }
    return pos;
/**
    It would be more efficient to use a variation of KMP to
    benefit from the failure function.
    - Algorithm inspired by James Kanze.
    - http://stackoverflow.com/questions/20406744/
*/
}
What a nice piece. The code is much cleaner than mine, lesser if statement, easier to digest with human brain. (Perfect!) Somehow, here is still better one. Believe or not, Boost library did have such algorithm developed:
    string work = "hello world";
    iterator_range<string::iterator> r = find_nth(work, "o", 1);
    cout << distance(work.begin(), r.begin()) << endl;
Wow!!! This piece was just damn real simple. From the top most till the bottom, although there are producing the same output, but the implementation was totally different. I can see the code is evolving gradually. What is next? What else can be done in the future? Fewer code?

Last but not least, thanks to Boost algorithm, nice work!

Tuesday, February 3, 2015

How to switch on C++11 on Eclipse?

This is, somehow, quite annoying me. I was compiling C++11 on Eclipse Kepler, but there was an error (as shown below) complaining to me that I must enable C++11 in order to proceed. But where is the C++11 switch?
Invoking: Cygwin C++ Compiler
g++ -I"D:\tool\boost_1_54_0" -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/main.d" -MT"src/main.d" -o "src/main.o" "../src/main.cpp"
In file included from /usr/lib/gcc/x86_64-pc-cygwin/4.8.3/include/c++/initializer_list:36:0,
                 from ../src/main.cpp:6:
/usr/lib/gcc/x86_64-pc-cygwin/4.8.3/include/c++/bits/c++0x_warning.h:32:2: error: #error This file requires compiler and library support for the ISO C++ 2011 standard. This support is currently experimental, and must be enabled with the -std=c++11 or -std=gnu++11 compiler options.
 #error This file requires compiler and library support for the \
  ^
In file included from D:\tool\boost_1_54_0/boost/filesystem/path_traits.hpp:23:0,
                 from D:\tool\boost_1_54_0/boost/filesystem/path.hpp:25,
                 from D:\tool\boost_1_54_0/boost/filesystem.hpp:16,
                 from ../src/main.cpp:7:
D:\tool\boost_1_54_0/boost/system/error_code.hpp:222:36: warning: 'boost::system::posix_category' defined but not used [-Wunused-variable]
src/subdir.mk:18: recipe for target 'src/main.o' failed
     static const error_category &  posix_category = generic_category();
                                    ^
D:\tool\boost_1_54_0/boost/system/error_code.hpp:223:36: warning: 'boost::system::errno_ecat' defined but not used [-Wunused-variable]
     static const error_category &  errno_ecat     = generic_category();
                                    ^
D:\tool\boost_1_54_0/boost/system/error_code.hpp:224:36: warning: 'boost::system::native_ecat' defined but not used [-Wunused-variable]
     static const error_category &  native_ecat    = system_category();

The switch was locate at project's properties > C/C++ Build > Settings > Tool Settings tab > Cygwin C++ Compiler > Miscellenous, put -std=c++11 in the Other Flags to switch on C++11 (append on it if it is not empty). Then the compilation will proceed as usual.

Unresolved inclusion on Eclipse

I have a C++ project which pretty well developed on Linux with Eclipse Kepler. Since this program is very well developed on Linux, I was thinking to have one Windows version as well. Since the development was done on Eclipse, the transition process should be super easy. But in fact, it wasn't.

I was using cygwin tool chain for my case, it doesn't compile as expected. There are so many unresolved error lying around, such as Unresolved inclusion: <iostream> is one of the example. This error was weird to me as the compiler was unable to find the header files. I was thinking this could be cause by cygwin path is different from regular path. Maybe path mapping could help? Go to project's properties > C/C++ > Debug >  Source Lookup Path, add a new path mapping as shown below:


Compilation path Local file system path
\cygdrive\c C:\
\cygdrive\d D:\

Since I got 2 partitions on my hard drive, I just put them all to let Eclipse search what it needs. Rebuild the project and the error still exists.

It took me a decade to work around this issue only realize that I was missing the configuration in C/C++ General > Preprocessor Include Paths, Macros etc > Providers tab > CDT GCC Builtin Compiler Settings Cygwin [shared] wasn't selected. Guess what? Without this option being selected, I suppose, to see the complain.

Tuesday, April 1, 2014

Compiling C code with Informix 4GL

When I was assigned a task that involve integration work between MQ and 4GL, this was really exciting me because this will involve C programming language since C is my favorite language. But one thing to note is that this is not the regular C I’ve been doing in the pass. It is highly dependent on the version of Informix version I’m currently running.

As I ask around, the Informix environment we are running is called Rapid Development System, RDS for short. In this enviroment, there is a program that used to make the C code, named cfglgo.v2. It is not a compiler, rather it is a P-code (pseudocode) runner. My senior told me that there are also c4gl or i4gl, but these are not usable in ours environment. Following is the example on how this runner is call:

cfglgo.v2 -I/opt/mqm/inc fgiusr.c myrunner.c /opt/mqm/lib64/libmqic.so -o myrunner

Following output should be seen after the execution on the above statement:
Reading specs from /usr/local/lib/gcc/sparc-sun-solaris2.10/3.4.6/specs
Configured with: ../configure --with-as=/usr/ccs/bin/as --with-ld=/usr/ccs/bin/ld --enable-shared --enable-languages=c,c++,f77
Thread model: posix
gcc version 3.4.6
 /usr/local/libexec/gcc/sparc-sun-solaris2.10/3.4.6/cc1 -quiet -v -I/usr/informix/incl/tools -I/usr/informix/incl/esql -I/opt/mqm/inc -D__arch64__ -D__sparcv9 fgiusr.c -mptr64 -mstack-bias -mno-v8plus -mcpu=v9 -quiet -dumpbase fgiusr.c -m64 -auxbase fgiusr -version -o /var/tmp//ccNzNEmS.s
ignoring nonexistent directory "NONE/include"
ignoring nonexistent directory "/usr/local/lib/gcc/sparc-sun-solaris2.10/3.4.6/../../../../sparc-sun-solaris2.10/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/informix/incl/tools
 /usr/informix/incl/esql
 /opt/mqm/inc
 /usr/local/include
 /usr/local/lib/gcc/sparc-sun-solaris2.10/3.4.6/include
 /usr/include
End of search list.
GNU C version 3.4.6 (sparc-sun-solaris2.10)
        compiled by GNU C version 3.3.2.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
 /usr/ccs/bin/as -V -Qy -s -xarch=v9 -o /var/tmp//cc4f9CWC.o /var/tmp//ccNzNEmS.s
/usr/ccs/bin/as: Sun Compiler Common 10 Patch 09/04/2007
 /usr/local/libexec/gcc/sparc-sun-solaris2.10/3.4.6/cc1 -quiet -v -I/usr/informix/incl/tools -I/usr/informix/incl/esql -I/opt/mqm/inc -D__arch64__ -D__sparcv9 myprogram.c -mptr64 -mstack-bias -mno-v8plus -mcpu=v9 -quiet -dumpbase myprogram.c -m64 -auxbase mqfunc -version -o /var/tmp//ccNzNEmS.s
ignoring nonexistent directory "NONE/include"
ignoring nonexistent directory "/usr/local/lib/gcc/sparc-sun-solaris2.10/3.4.6/../../../../sparc-sun-solaris2.10/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/informix/incl/tools
 /usr/informix/incl/esql
 /opt/mqm/inc
 /usr/local/include
 /usr/local/lib/gcc/sparc-sun-solaris2.10/3.4.6/include
 /usr/include
End of search list.
GNU C version 3.4.6 (sparc-sun-solaris2.10)
        compiled by GNU C version 3.3.2.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
 /usr/ccs/bin/as -V -Qy -s -xarch=v9 -o /var/tmp//ccv77fcB.o /var/tmp//ccNzNEmS.s
/usr/ccs/bin/as: Sun Compiler Common 10 Patch 09/04/2007
 /usr/local/libexec/gcc/sparc-sun-solaris2.10/3.4.6/collect2 -V -Y P,/usr/lib/sparcv9 -Qy -o fglmq /usr/local/lib/gcc/sparc-sun-solaris2.10/3.4.6/sparcv9/crt1.o /usr/local/lib/gcc/sparc-sun-solaris2.10/3.4.6/sparcv9/crti.o /usr/ccs/lib/sparcv9/values-Xa.o /usr/local/lib/gcc/sparc-sun-solaris2.10/3.4.6/sparcv9/crtbegin.o -L/usr/informix/lib -L/usr/informix/lib/esql -L/usr/informix/lib/lib/tools -L/usr/local/lib/gcc/sparc-sun-solaris2.10/3.4.6/sparcv9 -L/usr/local/lib/gcc/sparc-sun-solaris2.10/3.4.6 -L/usr/ccs/bin/sparcv9 -L/usr/ccs/bin -L/usr/ccs/lib/sparcv9 -L/usr/ccs/lib -L/usr/local/lib/gcc/sparc-sun-solaris2.10/3.4.6/../../../sparcv9 -L/usr/local/lib/gcc/sparc-sun-solaris2.10/3.4.6/../../.. -L/lib/sparcv9 -L/usr/lib/sparcv9 /var/tmp//cc4f9CWC.o /var/tmp//ccv77fcB.o /opt/mqm/lib64/libmqic.so /usr/informix/lib/tools/libfmain.a /usr/informix/lib/tools/libfglgo.a /usr/informix/lib/tools/lib4gl.a /usr/informix/lib/tools/lib4io.a /usr/informix/lib/tools/libnmenu.a /usr/informix/lib/tools/lib4io.a /usr/informix/lib/tools/librdsterm.a /usr/informix/lib/tools/libfmain.a /usr/informix/lib/tools/libfe.a /usr/informix/lib/tools/libfmain.a -ltermlib -liffgisql -lifasf -lifgen -lifos -lifgls -lnsl -lsocket -ldl -lm /usr/informix/lib/esql/checkapi.o -lifglx -laio -lm -ldl -lelf -ltermlib -lgcc -lgcc_eh -lc -lgcc -lgcc_eh -lc /usr/local/lib/gcc/sparc-sun-solaris2.10/3.4.6/sparcv9/crtend.o /usr/local/lib/gcc/sparc-sun-solaris2.10/3.4.6/sparcv9/crtn.o
ld: Software Generation Utilities - Solaris Link Editors: 5.10-1.1518

The final output of this will generate a custom runner called myrunner. This runner will contain the required C implementation that is needed to execute a 4GL program. On 4GL site, the program must compile using fglpc in order to link with the runner. Assuming the the_4gl_program.4gl has successfully compile into the_4gl_program.4go, this would be the step to launch 4GL program:

myrunner the_4gl_program

Saturday, February 8, 2014

Why Eclipse Kepler complaining invalid overload of endl?

This code cout << "blah blah blah" << endl; not suppose to be an error. Interestingly Eclipse Kepler state that this was an error:

Invalid overload of 'endl'

My mistake again? A stupid though passing by my brain, urging me to trying out this experiment:
    ...
    cout << "blah blah blah";
    cout << endl;
    ...
And this will compile OK. Miracle happen? Anyhow there is a cure for this problem:
  1. Windows menu > choose Preferences option > select Code Analysis on left panel.
  2. Under Syntax and Semantic Errors > change Invalid overload's severity from Error to Warning.
I wasn't really sure why Eclipse have such configuration, a message drop to Eclipse forum regarding this problem, and they reply that there was a fix on this error. Should be on the way on next release I guess.

Friday, November 22, 2013

May I know why Header file name must tally with CPP file name?

I must be very long time didn't code C++. Why this error could happened on yesterday? In my memory, it is not suppose be an error, is it only happened in Eclipse? Is it because I'm a long time Visual Studio fans?

The problem is very simple, I have a base class with virtual destructor declare in Base.h
    #ifndef BASE_H_
    #define BASE_H_

    class Base {
        public:
            Base();
            virtual ~Base();
    };
    #endif

And then I have a Child class inherited Base class declare in Child.h
    #ifndef CHILD_H_
    #define CHILD_H_

    #include "base.h"

    class Child : public Base {  // (1)
        public:
            Child();
    };
    #endif
Now make a main.cpp and put the implementation of Base class virtual destructor.
    #include "Base.h"

    Base::Base() {}

    Base::~Base() {}
When building the source code, there is an error complaining that undefined reference to 'Base::Base()' at (1). If I change main.cpp to Base.cpp, the error will gone. There are 2 possibility, it is either a new C++ specification or there isn't a compilation rules define for main.cpp in makefile. Later I found that the second option is making more sense on this. I didn't resolve the problem since the makefile is auto generated, if I make modification on it, I'm afraid this will generate another problem and my development time will be drag.

Tuesday, November 12, 2013

What is Delegating Constructor in C++?

Ahh... It has been so long I didn’t write any C++ code since 2010. While I was reading C++ article published at IBM’s website, I come across this term which I found very interesting and new to me. Consider following code snippet, all constructors use as a common initializer for its member variable.
class ClsA {
    private:
        int var;
        
    public:
        ClsA() : var(0) {}
        ClsA(int x) : var(x) {}
        
        ...
}
This is what I usually did at old school. Now there is slightly little improvement on the constructor syntax. Remember how the syntax applied when a member variable is initialized by a constructor. The same syntax can be applied to trigger another constructor to perform member variable initialization. This is what the syntax called delegating constructor. Consider:
class ClsA {
    private:
        int var;
        
    public:
        ClsA() : ClsA(123) {}    // (1)
        ClsA(int x) : var(x) {}  // (2)
        
        ...
};
When I do this:

ClsA clsA;

The constructor at (1) will get invoke and further call another constructor at (2) where member variable var get initialize to 123. The constructor at (1) is a delegating constructor, (2) is a target constructor. Somehow programmer still has the flexibility to invoke constructor at (2) directly to perform its initialization. More details on this specification can be found at open-std(dot)org.