Who is responsible for deleting the facet?

2019-03-12 01:30发布

问题:

I have a function that uses the Boost.DateTime library for generating the current GMT/UTC date and time string (live example).

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();
}

This is mostly based on Boost.DateTime's example:

//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"

My code worked nicely, but now I'm feeling uneasy because of these particular lines containing 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"));

As you can see, there is no delete in Boost.DateTime's so I somehow presumed that it is imperative for me to delete the date_facet. I used std::unique_ptr to wrap the newed time_facet object.

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

However, I am getting segfault errors, as you can see in here. I have also tried manually deleteing the newed pointer, and am still getting the same errors (sorry, can't reproduce error in Coliru).

The time_facet pointer is passed as an argument when constructing an std::locale object, so I'm confused who's the one responsible for deleteing the facet.

So here is the core of my question:

  • Am I required to delete the time_facet or is the std::locale object responsible for deleteing it?

Please note that boost::posix_time::time_facet is derived from boost::date_time::date_facet which is, in turn, derived from std::locale::facet. This question might generalized to std::locale::facet, though my problem is specific to time_facet.

Here are some docs on std::locale's constructors:

  • MSDN
  • cppreference.com

回答1:

Am I required to delete the time_facet or is the std::locale object responsible for deleteing the it?

You're not required to delete the time_facet so long as time_facet derives from std::locale::facet, which it should. The std::locale::facet is a base class that all facets should derive from that implement a form of reference counting. The standard says this:

§ 22.3.1.6

Once a facet reference is obtained from a locale object by calling use_facet<>, that reference remains usable, and the results from member functions of it may be cached and re-used, as long as some locale object refers to that facet.

Once all references of the facet are not being used, the destructor of std::locale will manage and delete references to the facet if its ref count is 0.

This is all specified in §22.3.1.1.2 in the C++11 standard. Where it states:

The refs argument to the constructor is used for lifetime management.

— For refs == 0, the implementation performs delete static_cast<locale::facet*>(f) (where f is a pointer to the facet) when the last locale object containing the facet is destroyed; for refs == 1, the implementation never destroys the facet.



回答2:

Not answering your question as others have already done it. But, it's really not required to construct the locale everytime.

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:

The locale is responsible for deleting the facet.



标签: c++ c++11 locale