[[ blog 이사 과정에서 정확한 posting날짜가 분실됨. 년도와 분기 정도는 맞지 않을까? ]]

There is copy construction in C++. And default copy constructor does shallow copy. But, we should take care of shallow-copied-instance. Every programmer knows about this issue. But, sometimes, it is difficult to detect mistake from shallow copy. Here is an example.

// a.h
class A
{
public:
    A(void){
        _ptr = NULL; _len = 0;
    }

    A(int len){
        _len = len;
        _ptr = malloc(_len);
    }

    ~A(void){
        if(NULL != _ptr) { free(_ptr); }
    }

    void*  _ptr
    int _len
};

-------

// file1.c
static A gA(100); // --- (*a)
void getA (A& param)
{
    A = gA;
}

// file2.c
void function (void)
{
    A localA; // --- (*1)
    getA(localA);
    ...
    // do something with localA.
    ...
}

In this case, 'localA'(*1)'s destructor is called at the moment of returning from the function. And at that time, memory of 'gA._ptr' is freed, because 'localA' is shallow copy of 'gA'.
Stack variable is automatically(implicitly) destructed when function is returned. And this is not easy to realize without keeping it in mind.

[[ blog 이사 과정에서 정확한 posting날짜가 분실됨. 년도와 분기 정도는 맞지 않을까? ]]

Reference is enhanced concept from Pointer in C++.
So, many C++ books says "Reference is better than Pointer. So try to use Reference if possible."
Yes, reference has several advantages. It guarantees that there is enough memory space for the variable. So, we don't need to do so-called "NULL Check" in most cases (In some evil cases, address can be NULL even if it is reference).
But, in terms of readability, sometimes, using Pointer is better than Reference. Since C, programmers think that parameter is passed by value. Let's see below.

func(a); // --- (*1)
func(&a); // --- (*2)

At first look - before looking at declaration of "func()", programmer tends to think that "Value of 'a' is passed. So, even after (*1), value of 'a' will be preserved." But in case of (*2), they might think that "Address of 'a' is passed. So, after (*2), value of 'a' may be changed."
But, Reference stands against of this 'Popular' concept - reference parameter of 'func()' may change value of 'a'.
But, in case that 'func()' doesn't change 'a', using reference - should be declared as 'const' - as parameter can be good choice.
In other words, if value of parameter is changed, using pointer is better then using reference in terms of readability, in my point of view.

In summary, my recommendation is,

"If possible, use Reference as parameter only when value of parameter is not changed with 'const' keyword."


[[ blog 이사 과정에서 정확한 posting날짜가 분실됨. 년도와 분기 정도는 맞지 않을까? ]]

At first, see [
 virtual method table in wikipedia ].

'pointer fixups' is needed to support inheritance in C++.
Let's dig deeper.. See following example. (classes comes from above Wikipedia).

// <CASE 1>
#ifdef _CASE_1_
class B1
{
public:
    void f0() {}
    virtual void f1() {}
    int int_in_b1;
};

class B2
{
public:
    virtual void f2() {}
    int int_in_b2;
};

class D : public B1, public B2
{
public:
    void d() {}
    void f2() {}  // override B2::f2()
    int int_in_d;
};
#endif // _CASE_1_

// <CASE 2>
#ifdef _CASE_2_
class B1
{
public:
    virtual ~B1(){}
    void f0() {}
    virtual void f1() {}
    int int_in_b1;
};

class B2
{
public:
    virtual ~B2(){}
    virtual void f2() {}
    int int_in_b2;
};
class D : public B1, public B2
{
public:
    ~D(){}
    void d() {}
    void f2() {}  // override B2::f2()
    int int_in_d;
};

#endif // _CASE_2_

void funcA(B1* obj) {
    // -------- (*1)
}

void funcB(B2* obj) {
    // -------- (*2)
}

void
main()
{
    D* p = new D;
    funcA(dynamic_cast<B1*>(p)); // -------- (*a)
    funcB(dynamic_cast<B2*>(p)); // -------- (*b)
    // delete p; // ----- (*l)
    // delete (dynamic_cast<B1*>(p)); // ----- (*m)
    // delete (dynamic_cast<B2*>(p)); // ----- (*n)
}

We can see that pointer 'p' is passed as parameter in (*a) and (*b). And to do this type-casting and 'pointer fixup' is needed. That is, actual memory address passed as parameter of (*a) is different from the one of (*b). This is 'pointer fixup'. In case of GCC and MSVC7, there is 8-byte-gap as above wikipedia said.; { Address_of_obj_at_(*1) + 8 = Address_of_obj_at_(*2) }.
That's OK. It's very common.

Then, what happen at the moment of deleting memory?
We may guess that memory address passed is same in (*l) and (*m), but not in (*n) - may be 8-byte-gap in GCC and MSVC7 same as the case of (*a) and (*b). In <CASE_1>, program works just as we expects. (*l) and (*m) don't make an exception at runtime, but (*n) does. Then, as you know, why <CASE_2> works well? Newly assigned memory is deleted correctly in <CASE_2>. Than, is it really true that passed addresses are different among (*l), (*m) and (*n)? To investigate deeper, I tested it again with overloaded new/delete operator.

void * operator new(size_t size) {
    return malloc(size);  // ------ (*A)
}

void operator delete(void *p) {
    return free(p); // ----- (*B)
}

We can check passed address at (*B). In <CASE_1>, 'p' at (*B) is same with 'obj' at (*2), and error is raised - memory address trying to free is different with allocated one. Difference between <CASE_1> and <CASE_2> is destructor declared as 'virtual'. Interestingly, in <CASE_2>, 'p' at (*B) is the value of 'obj' at (*1) - original address -, and work successfully. In summary, if 'virtual destructor' is defined, than original address value is passed to 'delete' operator. It is interesting, isn't it?. :-)

[[ blog 이사 과정에서 정확한 posting날짜가 분실됨. 년도와 분기 정도는 맞지 않을까? ]]

We can use 'typename' in template class.

template
class C
{
    typename T::bT* a;
}

But, keyword 'typename' cannot be used outside template. So, following is incorrect syntax.

class A;
class B
{
    A*     a;
    typename A::bT* b; // error here!
};

So, in this case, class A's definition should be included before definition of class B.

It's just small information about using 'typename'.

[[ blog 이사 과정에서 정확한 posting날짜가 분실됨. 년도와 분기 정도는 맞지 않을까? ]]

Throwing exception in C++ is very expensive operation. But, "try... catch..." itself doesn't drain performance if exception is not thrown. So, "Throwing exception" should not be used for just convenience in coding!! This should be used only to handle unexpected and not-often-raised exception!
[[ blog 이사 과정에서 정확한 posting날짜가 분실됨. 년도와 분기 정도는 맞지 않을까? ]]

Using "integer type" has lots of merits against using "float type"
So, in some cases - especially in embedded system that uses ARM as their main MCU - we want to change float-operation into integer-operation by multiplying or shifting it.
Yes! It's a good method in point of performance!
But we should take our careful attention to OVER/UNDERFLOW of integer-operation!!!
(In case of float-operation, in general, we are free from over/under flow!)

Keep in mind this.

[[ blog 이사 과정에서 정확한 posting날짜가 분실됨. 년도와 분기 정도는 맞지 않을까? ]]

There are two different API implementation to get data.

  // (*1) return, length of data remained.
  get_data(char* buffer /*in/out*/, int buffer_size/*in*/);

  // (*2) caller should free memory of (*data).
  get_data(char** data/*out*/, int* len/*out*/);

(*1) :
  This is very clear and safe, but inefficient in performance point of view and difficult to implement.
  And, the one who allocates memory, frees it too. (very reasonable. So, there is less risk of memory leak.)
(*2) : contrary to (*1)

Which one is better? In general, (*1) is recommended.

In terms of memory allocation/free, if possible, the one who allocates should free it. In case of this is not reasonable, at least, allocation-free-pair should be easy to track!

[[ blog 이사 과정에서 정확한 posting날짜가 분실됨. 년도와 분기 정도는 맞지 않을까? ]]

C++ doesn't support the 'interface' explicitly unlike Java. So, combination of abstract class and virtual function, is used.

Let's think of following case.

ModuleA
  A : pure abstract class (interface class).
  AImpl : implementation(concrete) class inherited from A.

External module that want to use ModuleA need to know interface, but don't need to know it's implementation. So, Knowing class A should be enough to use ModuleA. And this is tightly coupled with the way of instantiation.
Let's see below

A* instance = new AImpl(argument);

This is easy way. But, in this case, definition of 'AImpl' should be included in external code. This is not good in terms of 'Information Hiding'. We want to hide implementation details (even if it's header). See following example to do this.

----- A.h
class A // interface class
{
public:
    virtual ~A(){};
    static A* Create_instance(Arguments);
    int Interface_function_A(void) = 0;
    int Interface_function_B(void) = 0;
};

---- AImpl.h
#include "A.h"
class AImpl : private A
{
    friend class A;
    ...
}
...

---- A.cpp
#include "AImpl.h"
A::Create_instance(Arguments)
{
    AImpl* instance = new AImpl(Arguments);
    return static_cast(instance);
}

Now, knowing definition of class A is enough to use this module. Therefore, implementation details are completely hidden. Besides, inheriting as 'private', can prevent module from unexpected usage (AImpl can be used only through A). Here is sample usage.

#include "A.h"
...
A* instance = A::Create_instance(Arguments);
...
delete instance;

We made function for create instance. But, we should make destroying instance be possible by 'delete' keyword. Because, in many cases, knowing instance's concrete class at the moment of deleting it, is not necessary. And unifying interfaces to destroy instance (into using 'delete') is also good to read.

[[ blog 이사 과정에서 정확한 posting날짜가 분실됨. 년도와 분기 정도는 맞지 않을까? ]]

We should not access memory address directly to read the value.

For example,

Int8* pt;
malloc(pData, 6);
pt = pData;
*pt = length;
pt++;
*pt = width;
pt++
*pt = (int)size; // ---(*)

This may create unexpected result due to data align. See (*). At (*), address of 'pt' is not 4-byte-aligned. But, it tries to write 4-byte-data (integer value). In this case, result may be compiler or target architecture dependent - usually, 'size' will be written at 4-byte-aligned-address.
Programmer who wrote above code may intent to make following memory state.

pData : [length(1 byte)][width(1 byte)][size(4 bytes]

But, usually, this may create following or undefined result.

pData : [length(1 byte)][width(1 byte)][padding(2 bytes)][size(4 bytes)]

So, we should not use like above(accessing memory directly). We can use 'struct' instead.
But, use 'memcpy' if above way is really needed.

(*) ==> memcpy(pt, &size, sizeof(size));

We should always keep it mind that data is aligned. So, directly accessing memory address to read or write data always has risk of compatibility with align.

[[ blog 이사 과정에서 정확한 posting날짜가 분실됨. 년도와 분기 정도는 맞지 않을까? ]]

Let's remind about endianness.

big-endian : most significant byte first.
little-endian : least significant byte first.

How about following code?

UINT16 b;
UINT8* p;
p = &b;
b = 0xABCD;
printf("%x, %x\n", p[0], p[1]);

This make different result according to endianness.

LE : CD, AB
BE : AB, CD

So, avoid kind of coding!

+ Recent posts