Difference between revisions of "Short Notes on C/C++"

From PaskvilWiki
Jump to: navigation, search
 
Line 226: Line 226:
 
When writing <tt>a = b</tt>, where lvalue is on right hand side, ''copy constructor'' is used to construct the ''that'' parameter (object), thus swapping with it will do exactly what we need.
 
When writing <tt>a = b</tt>, where lvalue is on right hand side, ''copy constructor'' is used to construct the ''that'' parameter (object), thus swapping with it will do exactly what we need.
 
While with <tt>a = x + y</tt>, compiler will choose ''move constructor'' for initialization of ''that'', and then swapping will be equivalent to moving the data.
 
While with <tt>a = x + y</tt>, compiler will choose ''move constructor'' for initialization of ''that'', and then swapping will be equivalent to moving the data.
 +
 +
== Converting between <tt>std::string</tt> and <tt>std::wstring</tt> in C++11 ==
 +
 +
<pre>// one-liners
 +
std::wstring str = std::wstring_convert<std::condecvt_utf8<wchar_t>>().from_bytes("some string");
 +
std::string  str = std::wstring_convert<std::condecvt_utf8<wchar_t>>().to_bytes(L"some string");
 +
 +
// small functions
 +
std::wstring s2ws(const std::string& str)
 +
{
 +
    typedef std::codecvt_utf8<wchar_t> convert_type;
 +
    std::wstring_convert<convert_type, wchar_t> converter;
 +
    return converter.from_bytes(str);
 +
}
 +
 +
std::string ws2s(const std::wstring& str)
 +
{
 +
    typedef std::codecvt_utf8<wchar_t> convert_type;
 +
    std::wstring_convert<convert_type, wchar_t> converter;
 +
    return converter.to_bytes(str);
 +
}</pre>

Latest revision as of 15:06, 5 March 2014

How to clean up after child thread

Even when the child thread shuts down gracefully - i.e. the thread's function returns, or the thread calls pthread_exit() - there might still be a memory leak due to the thread data allocated during the call to pthread_create().

There are 3 options to handle this:

  • stop the thread from the creator thread using pthread_cancel(),
  • wait for the thread to shut down gracefully, and then pthread_join() with the thread (yes, "join with the stopped thread"); this call returns immediately, and frees up thread's resources,
  • have the thread clean up on its own, by pthread_detach()-ing the thread.

Non-blocking IO using sockets

To get a non-blocking IO, you can

  • set the socket to non-blocking:
// for fcntl()
#include <unistd.h>
#include <fcntl.h>
// for ioctl()
#include <sys/ioctl.h>

int set_nonblocking(int fd)
{
    int flags;
#if defined(O_NONBLOCK)
    if (-1 == (flags = fcntl(fd, F_GETFL, 0)))
        flags = 0;
    return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
#else
    flags = 1;
    return ioctl(fd, FIOBIO, &flags);
#endif
}
  • or, you can use MSG_DONTWAIT as flags in the calls to recv(), recvfrom(), send(), and sendto().

Or both... can't hurt. ;-)

Shared Libraries on Linux+GCC

Shared libraries on Linux typically name linker name, soname, and real name.

The linker name is typically "libtest.so". The soname is linker name with version, typically "libtest.so.1", and the real name is the name of the file, typically "libtest.so.1.0.3".

In reality, the "libtest.so.1.0.3" would be the actual file, with two links:

libtest.so.1 -> libtest.so.1.0.3
libtest.so   -> libtest.so.1

Example

Here's an example of "test_so" library - .h and .c files, how to build and link the .so file, and using this library from Python using ctypes.

test_so.h

#ifndef __TEST_SO__
#define __TEST_SO__

int test_so_string(const char* str);
int test_so_int(int i);

#endif//__TEST_SO__

test_so.c

#include "test_so.h"
#include <string.h>

int test_so_string(const char* str)
{
    return strlen(str);
}

int test_so_int(int i)
{
    return -i;
}

Compiling and Linking

gcc -fPIC -O3 -c -Wall test_so.c
gcc -shared -Wl,-soname,libtest_so.so.1 -o libtest_so.so.1.0.0 test_so.o -lc

Now, you can create also the "upper links":

ln -s libtest_so.so.1.0.0 libtest_so.so.1
ln -s libtest_so.so.1 libtest_so.so

Using from Python - test_so.py

import ctypes
lib = ctypes.CDLL("./libtest_so.so")

print "int -> int fcall works" if lib.test_so_int(1) == -1 else "int -> int fcall DOESN'T WORK!"
print "string -> int fcall works" if lib.test_so_string("hello there!") == 12 else "string -> int fcall DOESN'T WORK!"

will output:

$ python test_so.py 
int -> int fcall works
string -> int fcall works

See ctypes library for more info.

Notes

If your library needs for it's work to be used together with some other shared/dynamic library, you need to include -Wl,-export-dynamic option when creating the object file, so that linker exports all of the symbols, making it clear what all needs to be added for the library to work properly in the program that uses your library.

Singleton

Traditional Approach

// Singleton.h

class Singleton
{
private:
    Singleton() { }
    Singleton(const Singleton&) { }
    Singleton& operator=(const Singleton&) { }
    ~Singleton() { }
    static Singleton* inst;

public:
    static Singleton* instance();

};
// Singleton.cpp

#include "Singleton.h"

Singleton* Singleton::inst = NULL;  
  
Singleton* Singleton::instance()
{
    return inst ? inst : inst = new Singleton;
}

Stack-based Singleton

I usually prefer this version over the dynamically allocated one, as the destructor will be called (at some point in time), and allows you to free up all resources obtained during the lifetime - esp. close files, sockets, etc.

class Singleton
{
private:
    Singleton();
    Singleton(const Singleton&);
    Singleton& operator=(const Singleton&);
    ~Singleton();

    // ...

public:
    static Singleton& instance()
    {
        static Singleton inst;    // constructed on the first call
        return inst;
    }

    // ...

};

std::move Semantics

Mostly based on stackoverflow.com - What is move semantics?.

Consider simple string class, that manages it's string buffer. Thus follows the Rule of Three (if the class has either of the following, then it should probably have all of them - destructor, copy constructor, and copy assignment operator; in C++11 this has been extended to Rule of Five, adding move constructor, and move assignment operator - see further on).

#include <cstring>
#include <algorithm>

class string
{
    char* data;
    size_t size;

public:
    string(const char* p)
    {
        data = new char[size = strlen(p) + 1];
        memcpy(data, p, size);
    }

    ~string()
    {
        if (data)
            delete[] data;
    }

    string(const string& that)
    {
        data = new char[size = that.size];
        memcpy(data, that.data, size);
    }
};

This allows you to use the class in following expressions:

string a(x);                                    // (1)
string b(x + y);                                // (2)
string c(some_function_returning_a_string());   // (3)

Note that only in the case (1) the deep copy is actually necessary; cases (2) and (3) currently make a deep copy of temporary object (that itself was some deep copy of other objects). In case (1), the string object is lvalue, while in case (2) and (3) it's rvalue.

The C++11 introduces "rvalue reference", which allows us to detect rvalue via function overloading. We can then do pretty much anything with the object, as long as we leave it in some valid state (even though it's rvalue/temp object, its destructor will still be called). The move constructor would then be:

string::string(string&& that)
{
    data = that.data;
    size = that.size;
    that.data = 0;
    that.size = 0;
}

Here we pretty much stole the data, and since we're working with temp object, that gets destroyed in a moment, there's no problem doing so.

The move assignment operator is defined as

string& string::operator=(string that)
{
    std::swap(data, that.data);
    std::swap(size, that.size);
    return *this;
}

Note that we don't have the rvalue reference here; the compiler chooses the move constructor to create that object if the original object is rvalue.

When writing a = b, where lvalue is on right hand side, copy constructor is used to construct the that parameter (object), thus swapping with it will do exactly what we need. While with a = x + y, compiler will choose move constructor for initialization of that, and then swapping will be equivalent to moving the data.

Converting between std::string and std::wstring in C++11

// one-liners
std::wstring str = std::wstring_convert<std::condecvt_utf8<wchar_t>>().from_bytes("some string");
std::string  str = std::wstring_convert<std::condecvt_utf8<wchar_t>>().to_bytes(L"some string");

// small functions
std::wstring s2ws(const std::string& str)
{
    typedef std::codecvt_utf8<wchar_t> convert_type;
    std::wstring_convert<convert_type, wchar_t> converter;
    return converter.from_bytes(str);
}

std::string ws2s(const std::wstring& str)
{
    typedef std::codecvt_utf8<wchar_t> convert_type;
    std::wstring_convert<convert_type, wchar_t> converter;
    return converter.to_bytes(str);
}