In the mythical example in the previous section, we created two facet objects with operator new and incorporated them into locales, but we never deleted the facets with operator delete. This is poor coding for most objects, but for facet objects it is correct. Once a facet has been incorporated into a locale, the locale system takes over responsibility for deleting the facet when it is no longer needed, that is, when all locales that contain references to it have been destroyed.
This is a useful feature. For example, consider the following fragment:
using namespace std; cout.imbue(locale(locale(),new numpunct_byname<char>("de_DE"))); | | | | (4) (3) (1) (2)
What's happening here is fairly complex, so let's trace it out step by step:
We create a temporary locale object that is a copy of the current global locale.
We create a std::numpunct facet for a German locale.
We create another temporary locale which is a copy of the one created in (1), but with its std::numpunct facet replaced by the facet created in (2).
Using locale's copy constructor, we pass this locale by value to std::cout.imbue, which saves a copy of it in the stream object.
At the end of this operation, all the temporary objects are quietly destroyed, but a reference to the new std::numpunct facet remains behind in the locale object inside std::cout. Other functions can retrieve this object using std::cout.getloc(), and make copies of it and its facets. All in all, it would be a burden on an application to have to keep track of all this, in order to determine when it is safe to delete the std::numpunct_byname object. We can be grateful that the locale system takes care of this chore.
It is possible, but not recommended, to override this default behavior. The constructors of all the standard facets, and the constructor of the base class std::locale::facet, all take an integer parameter named refs, which defaults to 0 when you don't specify it. This is the usual case. If you specify it as 1 or some other positive integer, the locale system does not delete the facet.
This is necessary for facet objects that can't have the delete operator applied to them, for instance, because they were created on the stack or as static objects. To discourage you from creating facets this way, all the standard facets have protected destructors. The following code causes a compilation error:
static std::numpunct<char> my_static_np(1); // Error: no public // destructor int main () { std::numpunct_byname<char> my_np("de_DE",1); // Error: no public // destructor ... }
You can circumvent this protection by deriving a class with a public destructor from the standard facet. This may seem reasonable if you are going to use it only as a stand-alone object, and do not plan to incorporate it into any locale. For example, the following code lets you retrieve some data from the standard std::numpunct<char> facet without the overhead of new/delete:
class my_numpunct: public std::numpunct<char> { }; int main() { my_numpunct np; std::cout << np.truename() << " or " << np.falsename() << '?' << std::endl; ... }
However, the following code accomplishes the same thing even faster, because use_facet is very fast compared to the cost of calling most facets' constructors:
int main() { const std::numpunct<char>& np= std::use_facet<numpunct<char> >(std::locale::classic()); std::cout << np.truename() << " or " << np.falsename() << '?' << std::endl; ... }
In short, while it is possible to create facet objects on the stack, there is rarely a reason to do so. It is probably better to adapt a consistent policy of always creating facet objects with operator new. If you incorporate the facet into a locale, you do not need to delete it, and indeed, deleting it would be an error. If you never incorporate it into any locale, you should delete it when you are finished with it. Instead of creating and deleting a stand-alone facet in this case, however, it is usually possible (and faster) to accomplish the same thing by retrieving a reference to an existing facet from some locale.