C ++: ссылки и фабрики - PullRequest
       1

C ++: ссылки и фабрики

3 голосов
/ 03 апреля 2012

У меня есть что-то вроде этого:

struct D {
    virtual void operator() {...};
}
struct D1 : public D {
    virtual void operator() {...};
}
struct D2 : public D {
    virtual void operator() {...};
}

void foo(D &d) {...};

И так, это нормально, и прекрасно контролирует жизненный цикл моих D:

foo(D());
foo(D1());
foo(D2());

Но я выбираю свой вариант D в нескольких местах, поэтому я хочу простую фабрику:

const D& make_D()
{
    // BAD, returning reference to temporary
    if(is_tuesday())
        return D1();
    return D2();
}

Вместо того, чтобы возвращать ссылку на временный объект, я мог бы вернуть объект, но затем я разделил его до базового класса. В качестве альтернативы я мог бы вернуть указатель с моей фабрики, но тогда клиент должен удалить его. Другие, более сложные решения также увеличивают нагрузку на клиента.

Есть ли способ написать что-то вроде

D& d = make_D();
foo(d);

(или даже foo(make_D()))? Цель состоит в том, чтобы обернуть сложность в различные определения D и в make_D() так, чтобы такие функции, как foo() и те, кто вызывает эти функции, не беспокоились об этом.

Ответы [ 3 ]

5 голосов
/ 03 апреля 2012

К сожалению, это невозможно.

Обычно я использую std::unique_ptr (иногда std::shared_ptr, когда невозможно std::unique_ptr):

typedef std::unique_ptr< D > Dptr;
Dptr make_D()
{
    Dptr p( nulptr );

    if(is_tuesday())
        p.reset( new D1 );
    else
        p.reset( new D2 );

    return p;
}
5 голосов
/ 03 апреля 2012

Обычный способ - либо вернуть указатель, либо умный указатель.

Недостатком использования указателя является возможность пользователю управлять своей памятью.

Если вы возвращаете умный указатель, это больше не проблема.

const SmartPtr<D> make_D()
{
    if(is_tuesday())
        return SmartPtr(new D1());
    return SmartPtr(new D2());
}
0 голосов
/ 03 апреля 2012

Во-первых, я не слишком уверен, что понимаю.Код, который вы перечислили, не является законным и не будет компилироваться.Вы уверены, что это не:

struct D
{
    virtual void operator()() const { /* ... */ }
};

и:

void foo( D const& d ) { /* ... */ }

вызов или изменчивый?(Предположительно нет, поскольку вы не передаете никаких аргументов и отбрасываете объект после использования.) Если нет, то вы можете просто вернуть ссылки на статические экземпляры.Это обычное решение, которое я использую.В противном случае можно заставить копируемый объект вести себя полиморфно, используя идиому конверта буквы, но это немного трудоемко и требует значительных затрат времени выполнения, поскольку обычно требует клонирования фактического объекта для каждой копии.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...