Подтвердить что ты не робот

Кто несет ответственность за удаление грани?

У меня есть функция, которая использует библиотеку Boost.DateTime для генерации текущей строки даты и времени GMT/UTC (живой пример).

std::string get_curr_date() {
    auto date = boost::date_time::second_clock<boost::posix_time::ptime>::universal_time();

    boost::posix_time::time_facet* facet = new boost::posix_time::time_facet("%a, %d %b %Y %H:%M:%S GMT");

    std::ostringstream os;
    os.imbue(std::locale(os.getloc(), facet));
    os << date;

    return os.str();
}

В основном это основан на примере Boost.DateTime:

//example to customize output to be "LongWeekday LongMonthname day, year"
//                                  "%A %b %d, %Y"
date d(2005,Jun,25);
date_facet* facet(new date_facet("%A %B %d, %Y"));
std::cout.imbue(std::locale(std::cout.getloc(), facet));
std::cout << d << std::endl;
// "Saturday June 25, 2005"

Мой код работал красиво, но теперь я чувствую себя неловко из-за этих конкретных строк, содержащих new:

  • boost::posix_time::time_facet* facet = new boost::posix_time::time_facet("%a, %d %b %Y %H:%M:%S GMT");

  • date_facet* facet(new date_facet("%A %B %d, %Y"));

Как вы можете видеть, в Boost.DateTime нет delete, поэтому я как-то предположил, что для меня обязательно delete date_facet. Я использовал std::unique_ptr для обертывания объекта new ed time_facet.

std::unique_ptr<boost::posix_time::time_facet> facet(new boost::posix_time::time_facet("%a, %d %b %Y %H:%M:%S GMT"));

Однако я получаю ошибки segfault, как вы можете видеть в здесь. Я также попробовал вручную delete с указателем new ed, и все еще получаю те же ошибки (извините, не могу воспроизвести ошибку в Coliru).

Указатель time_facet передается как аргумент при построении объекта std::locale, поэтому я смущен тем, кто ответственен за delete за фасет.

Итак, вот суть моего вопроса:

  • Мне требуется delete time_facet или это объект std::locale, ответственный за delete за него?

Обратите внимание, что boost::posix_time::time_facet получен из boost::date_time::date_facet, который, в свою очередь, получен из std::locale::facet. Этот вопрос может быть обобщен на std::locale::facet, хотя моя проблема специфична для time_facet.

Вот несколько документов в конструкторах std::locale:

4b9b3361

Ответ 1

Мне нужно удалить time_facet или объект std:: locale ответственный за его удаление?

Вам не требуется удалять time_facet, пока time_facet происходит от std::locale::facet, что и должно быть. std::locale::facet - это базовый класс, из которого должны быть получены все грани, которые реализуют форму подсчета ссылок. В стандарте говорится следующее:

§ 22.3.1.6

Как только ссылка на грань получается из объекта локали, вызвав use_facet<>, эта ссылка остается пригодной для использования, а результаты функции-члены могут быть кэшированы и повторно использованы, если некоторые объект locale относится к этой грани.

Когда все ссылки фасета не используются, деструктор std::locale будет обрабатывать и удалять ссылки на фасет, если его количество ссылок равно 0.

Все это указано в разделе 22.3.1.1.2 в стандарте С++ 11. Где он указывает:

Аргумент refs для конструктора используется для управления жизненным циклом.

- для refs == 0 реализация выполняет delete static_cast<locale::facet*>(f) (где f - указатель на фасет) когда уничтожается последний объект локали, содержащий грань; для refs == 1, реализация никогда не разрушает грань.

Ответ 2

Не отвечая на ваш вопрос, как это уже сделали другие. Но на самом деле это не требуется для создания локали каждый раз.

std::string get_curr_date_time() {
    namespace bpt = boost::posix_time;
    namespace bdt = boost::date_time;
    std::ostringstream os;
    auto date = bdt::second_clock<bpt::ptime>::universal_time();
    const static std::locale currlocale (os.getloc(), new bpt::time_facet("%Y%m%d%H%M%S"));
    boost::posix_time::time_facet* facet = new boost::posix_time::time_facet("%a, %d %b %Y %H:%M:%S GMT");

    os.imbue(currlocale);
    os << date;
    return os.str();
}

Ответ 3

Локаль отвечает за удаление грани.