Why the bad_alloc(const char*) was made private in Visual C++ 2012?

↘锁芯ラ 提交于 2019-12-01 16:44:44

The C++11 Standard defines bad_alloc as such (18.6.2.1):

class bad_alloc : public exception {
public:
    bad_alloc() noexcept;
    bad_alloc(const bad_alloc&) noexcept;
    bad_alloc& operator=(const bad_alloc&) noexcept;
    virtual const char* what() const noexcept;
};

With no constructor that takes a string. A vendor providing such a constructor would make the code using it not portable, as other vendors are not obliged to provide it.

The C++03 standard defines a similar set of constructors, so VS didn't follow this part of the standard even before C++11. MS does try to make VS as standard compliant as possible, so they've probably just used the occasion (new VS, new standard) to fix an incompatibility.

Edit: Now that I've seen VS2012's code, it is also clear why the mentioned constructor is left private, instead of being completely removed: there seems to be only one use of that constructor, in the bad_array_new_length class. So bad_array_new_length is declared a friend in bad_alloc, and can therefore use that private constructor. This dependency could have been avoided if bad_array_new_length just stored the message in the pointer used by what(), but it's not a lot of code anyway.

If you are accustomed to passing a message when you throw a std::bad_alloc, a suitable technique is to define an internal class that derives from std::bad_alloc, and override ‘what’ to supply the appropriate message.

You can make the class public and call the assignment constructor directly, or make a helper function, such as throw_bad_alloc, which takes the parameters (and additional scalar information) and stores them in the internal class.

The message is not formatted until ‘what’ is called. In this way, stack unwinding may have freed some memory so the message can be formatted with the actual reason (memory exhaustion, bad request size, heap corruption, etc.) at the catch site. If formatting fails, simply assign and return a static message.

Trimmed example:

(Tip: The copy constructor can just assign _Message to nullptr, rather than copy the message since the message is formatted on demand. The move constructor, of course can just confiscate it :-).

class internal_bad_alloc: public std::bad_alloc
   {
   public:
      // Default, copy and move constructors....

      // Assignment constructor...
      explicit internal_bad_alloc(int errno, size_t size, etc...) noexcept:
         std::bad_alloc()
         {
         // Assign data members...
         }

      virtual ~internal_bad_alloc(void) noexcept
         {
         // Free _Message data member (if allocated).
         }

      // Override to format and return the reason:
      virtual const char* what(void) const noexcept
         {
         if (_Message == nullptr)
            {
            // Format and assign _Message.  Assign the default if the
            // format fails...
            }
         return _Message;
         }

   private:
      // Additional scalar data (error code, size, etc.) pass into the
      // constructor and used when the message is formatted by 'what'...
      mutable char* _Message;
      static  char  _Default[];
   }
};

//
// Throw helper(s)...
//
extern void throw_bad_alloc(int errno, size_t size, etc...)
   {
   throw internal_bad_alloc(errno, size, etc...);
   }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!