Performance Notes

In order for a class wrapper to produce equivalent assembly as the wrapped type (e.g. a raw pointer, integer, ...), it must satisfy certain traits that in general are dependent on the platform ABI.

Any class (no matter how complicated) will be optimized out in all cases, except when passed as an argument to or returned from a function. The argument passing conventions depend on the platform ABI, but in general, simple types like raw pointers or integers as well as small classes of certain type will be passed in registers (i.e. by value), while big classes on a stack (by reference).

Example1: g++ 4.8.2, 4.9.2, 5.1.0 on 64bit will pass classes by value if and only if the class is trivially copyable and its size (measured using sizeof) is less or equal to 16 bytes.

Example2: icpc 15.0.1 on 64bit will pass by value if and only if the class is trivially copyable and size less or equal to 16 bytes.

Other platforms might differ. Some authors propose to pass classes by value if they are trivially copyable as well as a standard layout type. So it is probably a good idea to make it both trivially copyable as well as a standard layout type. However, it does not seem to need to have a trivial default constructor (i.e. neither trivial nor a POD seems to be required).

Type Traits

If the class is trivially copyable (std::is_trivially_copyable) as well as has a trivial default constructor (std::is_trivially_default_constructible) then it is trivial (std::is_trivial). If in addition it is a standard layout type (std::is_standard_layout), then it is a POD (std::is_pod).

Example 1

Old:

int *a;
{
    int b=1;
    a = &b;
}
*a = 5; // Dangling, undefined behavior

New:

Ptr<int> a;
{
#ifdef DEBUG_MODE
    UniquePtr<int> b(new int(1));
#else
    int b=1;
#endif
#ifdef DEBUG_MODE
    a = b.ptr();
#else
    a = ptrFromRef(b);
#endif
}
*a = 5; // Dangling, throws an exception in Debug mode

Example 2

Old:

class A {
private:
    std::map<int, int> m;
public:
    std::map<int, int> *get_access() {
        return &m;
    }
};

New:

class A {
private:
#ifdef DEBUG_MODE
    UniquePtr<std::map<int, int>> m;
#else
    std::map<int, int> m;
#endif
public:
    Ptr<std::map<int, int>> get_access() {
#ifdef DEBUG_MODE
        return m.ptr();
#else
        return ptrFromRef(m);
#endif
    }
};

Example 3

Code (original):

UserIdentity *IdentityManager::lookupHostname(const QString &hostname) const
{
    QString ohost = ContactIDValidator::hostnameFromID(hostname);
    if (ohost.isNull())
        ohost = hostname;

    if (!ohost.endsWith(QLatin1String(".onion")))
        ohost.append(QLatin1String(".onion"));

    for (QList<UserIdentity*>::ConstIterator it = m_identities.begin(); it != m_identities.end(); ++it)
    {
        if (ohost.compare((*it)->hostname(), Qt::CaseInsensitive) == 0)
            return *it;
    }

    return 0;
}

Code (original):

ContactUser *ContactIDValidator::matchingContact(const QString &text) const
{
    ContactUser *u = 0;
    if (m_uniqueIdentity)
        u = m_uniqueIdentity->contacts.lookupHostname(text);
    return u;
}

And (original):

void UserIdentity::handleIncomingAuthedConnection(Connection *conn)
{
    if (conn->purpose() != Connection::Purpose::Unknown)
        return;

    QString clientName = conn->authenticatedIdentity(Connection::HiddenServiceAuth);
    if (clientName.isEmpty()) {
        BUG() << "Called to handle incoming authed connection without any authed name";
        return;
    }

    ContactUser *user = contacts.lookupHostname(clientName);
    if (!user) {
        // This client can start a contact request, for example. The purpose stays unknown, and the
        // connection will be killed if the purpose isn't changed before the timeout.
        qDebug() << "Have an incoming connection authenticated as unknown client" << clientName;
        return;
    }

    qDebug() << "Incoming connection authenticated as contact" << user->uniqueID << "with hostname" << clientName;
    user->assignConnection(conn);

    if (conn->parent() != user) {
        BUG() << "Connection wasn't claimed after authentication";
        conn->close();
    }
}