Home > database >  Different ways of initializing an object inside of a structure
Different ways of initializing an object inside of a structure

Time:12-20

I have following class:

// NetworkManager.hpp
class NetworkManager : public QObject {
    Q_OBJECT

public:
    NetworkManager(QHostAddress const& address, quint16 port);

private:
    QHostAddress const& _address;
    quint16 const _port;
};

// NetworkManager.cpp
NetworkManager(QHostAddress const& address, quint16 const port)
    : _address(address)
    , _port(port)
{
}

This class included in a structure:

struct Context {
    NetworkManager networkManager
};

I initialize this structure like this:

class A {
public:
    A() : _context({{QHostAddress::SpecialAddress::LocalHost, 1337}})
    {
    }

private:
    Context _context;
};

The problem is when the structure is getting initialized, it calls NetworkManager copy constructor, which is deleted by default, because it inherits QObject. But when I use different initialization, _context{{QHostAddress::SpecialAddress::LocalHost, 1337}}, everything works fine. Why does it happen?

I use Clang compiler and C 20 standard.

CodePudding user response:

The first code example is constructing a temporary object which then gets passed to _context's copy constructor.

_context({{QHostAddress::SpecialAddress::LocalHost, 1337}}) is basically the same as

Context temp(QHostAddress::SpecialAddress::LocalHost, 1337);
Context _context(temp);

The second example, _context{{QHostAddress::SpecialAddress::LocalHost, 1337}} is constructing the _context object in place, no temporary is created so no copy is performed.

CodePudding user response:

The issue is caused by the difference in the initializer list syntax between the two initializations:

A() : _context({{QHostAddress::SpecialAddress::LocalHost, 1337}})

and

A() : _context{{QHostAddress::SpecialAddress::LocalHost, 1337}}

In the first case, the outer curly braces {} create a new inner initializer list, while in the second case they are part of the same initializer list as the outer initializer list. This means that in the first case, the NetworkManager constructor is being called with a single argument, which is an initializer list, while in the second case, it is being called with two arguments, which are the QHostAddress and quint16 values.

Since the NetworkManager constructor takes two arguments, the first initialization will try to call the copy constructor, which is deleted by default because NetworkManager inherits from QObject. This causes a compile error.

On the other hand, the second initialization is correct because it passes the correct number of arguments to the NetworkManager constructor.

To fix the issue, you can either use the second initialization syntax, or define a custom copy constructor for NetworkManager to allow it to be copied.

  • Related