C C QA - yszheda/wiki GitHub Wiki

C++/C QA

C

Pointer

// an integer
int a;
// a pointer to an integer
int* a;
// a pointer to a pointer to an integer
int** a;
// an array of 10 integers
int a[10];
// an array of 10 pointers to integers
int* a[10];
// a pointer to an array of 10 integers
int (*a)[10];
// a pointer to a function that takes an integer argument and returns an integer
int (*a)(int);
// a function that takes an integer argument and returns a pointer to an integer
int *a(int);
// an array of 10 pointers to functions that take an integer argument and return an integer
int (*a[10])(int);

restrict

volatile

Character Constant

In C, the type of a character constant like 'a' is actually an int, with size of 4. In C++, the type is char, with size of 1.

References

http://david.tribble.com/text/cdiffs.htm

extern "C"

Const

  • C++: a const that is outside all functions has file scope (default to internal linkage)

  • C defaults to external linkage for consts, while C++ defaults to internal linkage for consts.

  • In C++, a const doesn't necessarily create storage, while in C a const always creates storage.

// pointer to const
const int* p;
int const* p;
// const pointer
int * const p;
// const pointer to const
const int* const p;
int const* const p;
// const reference
const int& ref;
  • Temporary objects are always const -> use const references as function arguments to receive temporary objects.

  • static const member: compile-time constant

class A
{
	static const int size = 100;
	int i[size];
}

"enum hack" for old compiler

class A
{
	enum { size = 100 };
	int i[size];
}
  • mutable variable: can be changed inside a const object

Empty Class

Size of empty class

Empty base optimization

Class default member functions

member initialization list

Pointer vs Reference

  • A reference must always be initialized because the object it refers to already exists; a pointer can be initialized at any time.
  • Once a reference is initialized to an object, it cannot be changed to refer to another object; a pointer can be pointed to another object at any time.
  • There is no NULL references.

Polymorphism & Virtual Functions

  • The virtual mechanism doesn't work with the constructor and destructor.
    • If you call a virtual function inside a constructor, only the local version of the function is used.
    • If you call a virtual function inside a destructor, only the local version of the function is used.

Operator Overloading

Cannot be overloadded

  • . (Member Access or Dot operator)

  • ?: (Ternary or Conditional Operator )

  • :: (Scope Resolution Operator)

  • .* (Pointer-to-member Operator )

  • sizeof (Object size Operator)

  • typeid (Object type Operator)

Assignment

Check self-assignment!

class Byte
{
	unsigned char b;
public:
	Byte(unsigned char bb = 0): b(bb) {}
	Byte(const Byte& other) { this.b = other.b }
	Byte& operator=(const Byte& right)
	{
		if( this == &right )
		{
			return *this;
		}
		b = right.b;
		return *this;
	}
}

Increment & Decrement

  • prefix ++/-- : unary

  • postfix ++/-- : binary

class Byte
{
	unsigned char b;
public:
	Byte(unsigned char bb = 0): b(bb) {}
	Byte(const Byte& other) { this.b = other.b }
	Byte& operator=(const Byte& right)
	{
		if( this == &right )
		{
			return *this;
		}
		b = right.b;
		return *this;
	}
	// prefix: ++Byte
	const Byte& operator++()
	{
		b ++;
		return *this;
	}
	// postfix: Byte++
	const Byte& operator++(int)
	{
		Byte before(b);
		b ++;
		return before;
	}
}

Operator Conversion

No return type!

class A {};
class B
{
	public:
		operator A() const { return A(); }
};

Object memory layout

virtual table

C++ vs Java

  1. Java runs in a virtual machine.
  2. C++ natively supports unsigned arithmetic.
  3. In Java, parameters are always passed by value (or, with objects, their references are passed by value). In C++, parameters can be passed by value, pointer, or by reference.
  4. Java has built-in garbage collection.
  5. C++ allows operator overloading.
  6. C++ allows multiple inheritance of classes.

C++ Exception

Debug

In gdb:

(gdb) catch throw

multiple inheritance


What are some disciplines for using multiple inheritance?

  • M.I. rule of thumb #1: Use inheritance only if doing so will remove if / switch statements from the caller code.
    • inheritance is not for code-reuse.
    • the primary purpose for inheritance is dynamic binding, and that is for flexibility.
    • Composition is for code reuse, inheritance is for flexibility.
  • M.I. rule of thumb #2: Try especially hard to use ABCs when you use MI.
    • this rule of thumb tends to push people toward inheritance-for-interface-substitutability, which is always safe, and away from inheritance-just-to-help-me-write-less-code-in-my-derived-class, which is often (not always) unsafe.
  • M.I. rule of thumb #3: Consider the “bridge” pattern or nested generalization as possible alternatives to multiple inheritance.

getopt

cast

const_cast

dynamic_cast

Preprocessor

##

compile-time print macro

__FILE__

#include <string.h>

#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)

__PRETTY_FUNCTION__ __FUNCTION__

OS-specified macros

$ touch dummy.hxx
$ cpp -dM ./dummy.hxx
#define __DBL_MIN_EXP__ (-1021)
#define __FLT_MIN__ 1.17549435e-38F
#define __CHAR_BIT__ 8
#define __WCHAR_MAX__ 2147483647
#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
#define __FLT_EVAL_METHOD__ 0
#define __DBL_MIN_10_EXP__ (-307)
#define __FINITE_MATH_ONLY__ 0
#define __SHRT_MAX__ 32767
#define __LDBL_MAX__ 1.18973149535723176502e+4932L
#define __UINTMAX_TYPE__ long unsigned int
#define __linux 1
#define __unix 1
#define __linux__ 1
...

__VA_ARGS__

#define VARIADIC_SIZE(...) std::tuple_size<decltype(std::make_tuple(__VA_ARGS__))>::value

binary compatible

reflection

create object by class name

template<class Interface, class KeyT=std::string>
struct Factory {
    typedef KeyT Key;
    typedef std::auto_ptr<Interface> Type;
    typedef Type (*Creator)();

    bool define(Key const& key, Creator v) {
        // Define key -> v relationship, return whether this is a new key.
        return _registry.insert(typename Registry::value_type(key, v)).second;
    }
    Type create(Key const& key) {
        typename Registry::const_iterator i = _registry.find(key);
        if (i == _registry.end()) {
            throw std::invalid_argument(std::string(__PRETTY_FUNCTION__) +
                                        ": key not registered");
        }
        else return i->second();
    }

    template<class Base, class Actual>
    static
    std::auto_ptr<Base> create_func() {
        return std::auto_ptr<Base>(new Actual());
    }

private:
    typedef std::map<Key, Creator> Registry;
    Registry _registry;
};

Problem-shooting

enum to string

Initialize vector from c array

int a[];
int *ptr;
int cnt;
vector v1(a, std::end(a));
vector v2(ptr, ptr+cnt);
vector v3;
v3.assign(a, std::end(a));

redefinition of default argument

Floating point exception

no known conversion from 'const char ' to 'std::string &'

message for cassert

assert(a == b && "A is not equal to B");
assert(("A must be equal to B", a == b));
#ifndef NDEBUG
#   define ASSERT(condition, message) \
    do { \
        if (! (condition)) { \
            std::cerr << "Assertion `" #condition "` failed in " << __FILE__ \
                      << " line " << __LINE__ << ": " << message << std::endl; \
            std::terminate(); \
        } \
    } while (false)
#else
#   define ASSERT(condition, message) do { } while (false)
#endif

NDEBUG

pass 1D array as parameter

template<size_t n> double f(double (&c)[n]);

pass 2D array as parameter

template <size_t rows, size_t cols>
void process_2d_array_template(int (&array)[rows][cols])
{
    std::cout << __func__ << std::endl;
    for (size_t i = 0; i < rows; ++i)
    {
        std::cout << i << ": ";
        for (size_t j = 0; j < cols; ++j)
            std::cout << array[i][j] << '\t';
        std::cout << std::endl;
    }
}

namespace function: unresolved external symbol

multiple definition of template specialization

there are no arguments to 'memcpy' that depend on a template parameter, so a declaration of 'memcpy' must be available

hide private function in header

Use unique_ptr in pImpl

'to_string' is not a member of 'std'

#include <string>
#include <sstream>

template <typename T> std::string to_string(const T& n)
{
    std::ostringstream stm;
    stm << n;
    return stm.str();
}

terminate called after throwing an instance of 'std::system_error' what(): Enable multithreading to use std::thread: Operation not permitted

-pthread

malloc(): memory corruption:

‘itoa’ was not declared in this scope

sprintf(aval,"%d",ival);

‘std::stringstream’ has no member named ‘swap’

Explicit specialization in non-namespace scope

print int64_t in C

#include <inttypes.h>

int64_t t;
printf("%" PRId64 "\n", t);

uint64_t i;
printf("%" PRIu64 "\n", i);

call of overloaded ‘abs(const value_type&)’ is ambiguous

#include <cmath>
#include <cstdlib>

warning: ISO C++11 requires at least one argument for the "..." in a variadic macro

error: ‘__closure’ is not a constant expression

sYSMALLOc: Assertion

malloc.c:3096: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char *)
&((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd))))
&& old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)
((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))
+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1)))
&& ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed.

call to function 'operator<<' that is neither visible in the template definition nor found by argument-dependent lookup

inheritance of nested classes

template friend class in template class

source type is not polymorphic

Template std::function as class member function

inspect private member

C default arguments

void f_impl(int a, float b) {
  printf("%d %g\n", a, b);
}

#define f_impl(...) f_macro(__VA_ARGS__, 3.7)
#define f_macro(a, b, ...) f_impl(a, b)
⚠️ **GitHub.com Fallback** ⚠️