Можно ли иметь реализацию члена для обмена броска? - PullRequest
4 голосов
/ 05 октября 2011

Общая рекомендация при написании классов (с использованием идиомы копирования и замены) заключается в предоставлении функции-члена без броска подкачки. ( Вступление в силу C ++, 3-е издание, пункт 25 и другие ресурсы)

Однако что, если я не могу предоставить гарантию nothrow, потому что в моем классе используется сторонний член класса, который не предоставляет операции подкачки?

// Warning: Toy code !!!

class NumberBuffer {
public:
    ...
    void swap(NumberBuffer& rhs);

public:
    float* m_data;
    size_t m_n;
    CString m_desc;
};

void swap(NumberBuffer& lhs, NumberBuffer& rhs) {
    lhs.swap(rhs);
}

void NumberBuffer::swap(NumberBuffer& rhs) {
    using std::swap;
    swap(m_data, rhs.m_data);
    swap(m_n, rhs.m_n);
    swap(m_desc, rhs.m_desc); // could throw if CString IsLocked and out-of-mem
}

CString swap не может быть выполнен без броска, так что есть вероятность, что своп не удастся.

Примечание: для редких сторонних классов можно использовать интеллектуальное ptr (pimpl), , но -

Примечание: CString - хороший пример, поскольку никто в здравом уме (?) Не начал бы удерживать всех членов концептуально простого и вездесущего класса, такого как CString, через pimpl (smart ptr), потому что это действительно выглядело бы ужасно - и на с другой стороны, нет (в краткосрочном и среднесрочном плане) шансов изменить CString, чтобы разрешить полный обмен без бросков.

Итак, нормально ли иметь потенциально вызывающую функцию-член подкачки, если вы не можете помочь ей ? (Или вы знаете пути решения этой головоломки?)

Редактировать: И: Можно ли использовать бросающий элемент обмена с идиомой копирования и обмена, чтобы обеспечить базовую гарантию, если не сильную гарантию?

Ответы [ 3 ]

3 голосов
/ 05 октября 2011

Итак, нормально ли иметь потенциально вызывающую функцию-член подкачки, если вы не можете помочь? (Или вы знаете пути решения этой головоломки?)

Нет ничего по сути неправильного с наличием функции swap, которая может потенциально генерировать, но имейте в виду, что без строгой гарантии исключения в swap она не может быть использована для обеспечения безопасности исключений, что то есть, его можно использовать только как swap (то есть забыть об идиоме копирования и замены для этого конкретного класса в качестве способа предоставления гарантии строгого исключения ... но вы все равно можете использовать его для уменьшения суммы кода - и документ, который не является безопасным для исключения)

В качестве альтернативы, вы можете переместить CString в интеллектуальный указатель, который предлагает не-бросок swap (или, по крайней мере, сильную гарантию исключения), не очень хорошее решение, но, по крайней мере, оно будет безопасным для исключения , Наконец, вы можете полностью отказаться от CString, используя любую другую библиотеку строк, которая предоставляет все, что вам нужно, и предлагает операцию замены без бросков.

2 голосов
/ 05 октября 2011

Нет ничего плохого в броске swap, он просто менее полезен, чем версия без бросков.

Идиома копирования и обмена не нуждается в swap, чтобы быть безбрасыванием вЧтобы обеспечить сильную исключительную гарантию.swap требуется только для предоставления гарантии сильного исключения.

Сложность состоит в том, что если гарантия без броска не может быть предоставлена, также вероятно, что гарантия сильного исключения не может быть предоставлена.Простое свопирование с использованием временных и трех копий обеспечивает только базовую гарантию, если только операция копирования не обеспечивает гарантию безбрасывания, в этом случае своп также является безбрасыванием.

0 голосов
/ 05 октября 2011

Вы можете легко сделать это в два раза:

void NumberBuffer::swap(NumberBuffer& rhs) throw()
{
    try
    {
        std::swap(m_desc, rhs.m_desc);   //could throw
        std::swap(m_data, rhs.m_data);
        std::swap(m_n, rhs.m_n);
    }
    catch(...)
    {
    }
}

Конечно, это не реальное решение проблемы, но теперь вы по крайней мере получили своп без броска;)

...