nondynamic: A utility class that promotes safe programming

Hi there! (I recently posted a similar message to microsoft.public.vc.language, but the response was so bad I thought I would post here instead.) I have created a utility class that I think is useful, called nondynamic. The purpose is sort of like boost::noncopyable, but I disallow any dynamic/ pointer usages. For example, & and -> are disabled. Operator new/delete as well. Let me show nondynamic: // all members are private class nondynamic { // disallow operator new static void* operator new(std::size_t); static void* operator new(std::size_t, const std::nothrow_t&) throw(); static void* operator new[](std::size_t); static void* operator new[](std::size_t, const std::nothrow_t&) throw(); // disallow operator delete static void operator delete(void*){} static void operator delete(void*, const std::nothrow_t&) throw(){} static void operator delete[](void*){} static void operator delete[](void*, const std::nothrow_t&) throw(){} // disallow address-of const nondynamic* operator&() const; /* */ nondynamic* operator&() /* */; // disallow -> const nondynamic* operator->() const; /* */ nondynamic* operator->() /* */; }; Using this class is as simple as using boost::noncopyable: struct DataIO : private nondynamic { ... }; Now you are only able to use DataIO as a value type. All other usages are disabled. I think this promotes safe programming, in that pointer usage is minimized (it seems with pointers, new/delete/null is never far away). Let me illustrate how this class can be used most effectively. I thought it would be nice to use nondynamic when you have a class hierarchy, and a factory method. Here's the base class: struct IDataIO { virtual void Write(const std::string& str) = 0; virtual void Read(char* buffer, std::size_t size) = 0; }; typedef boost::shared_ptr<IDataIO> IDataIOPtr; A sample subclass: struct SerialDataIO : IDataIO { void Write(const std::string&) { std::cout << __FUNCTION__ << std::endl; } void Read(char*, std::size_t) { std::cout << __FUNCTION__ << std::endl; } }; Here's the wrapper class that inherits from nondynamic: struct DataIO : IDataIO, private nondynamic { DataIO(IDataIOPtr dataIO) : mDataIO(dataIO) {} void Write(const std::string& str) { mDataIO->Write(str); } void Read(char* buffer, std::size_t size) { mDataIO->Read(buffer, size); } private: IDataIOPtr mDataIO; }; And finally, the factory: DataIO CreateDataIO(int i) { if( i==0 ) return IDataIOPtr(new SerialDataIO); else throw std::runtime_error("Could not create DataIO"); } Now the clients of the class hierarchy uses the wrapper, and are completely isolated from pointers: DataIO dataIO = CreateDataIO(0); dataIO.Write("Hello"); char buffer[1024]; dataIO.Read(buffer, sizeof(buffer)); It should be impossible to misuse DataIO. What do you think about nondynamic? Is it implemented correctly? Named appropriately? Useful at all? Any comments gladly accepted :-) Thanks in advance! -- Daniel

Hello Daniel,
I thought about such a class as well. The main disadvantage of it is that it
is impossible to use with standard containers. :(
Standard containers (e.g. std::vector) pre-allocate space for some number of
instances and use the placement new operator to place items in the
pre-allocated memory and when deriving form
nondynamic makes it impossible.
With kind regards,
Ovanes
On Fri, Mar 28, 2008 at 10:40 AM, Daniel Lidström
Hi there!
(I recently posted a similar message to microsoft.public.vc.language, but the response was so bad I thought I would post here instead.)
I have created a utility class that I think is useful, called nondynamic. The purpose is sort of like boost::noncopyable, but I disallow any dynamic/ pointer usages. For example, & and -> are disabled. Operator new/delete as well. Let me show nondynamic:
// all members are private class nondynamic { // disallow operator new static void* operator new(std::size_t); static void* operator new(std::size_t, const std::nothrow_t&) throw(); static void* operator new[](std::size_t); static void* operator new[](std::size_t, const std::nothrow_t&) throw();
// disallow operator delete static void operator delete(void*){} static void operator delete(void*, const std::nothrow_t&) throw(){} static void operator delete[](void*){} static void operator delete[](void*, const std::nothrow_t&) throw(){}
// disallow address-of const nondynamic* operator&() const; /* */ nondynamic* operator&() /* */;
// disallow -> const nondynamic* operator->() const; /* */ nondynamic* operator->() /* */; };
Using this class is as simple as using boost::noncopyable:
struct DataIO : private nondynamic { ... };
Now you are only able to use DataIO as a value type. All other usages are disabled. I think this promotes safe programming, in that pointer usage is minimized (it seems with pointers, new/delete/null is never far away).
Let me illustrate how this class can be used most effectively. I thought it would be nice to use nondynamic when you have a class hierarchy, and a factory method.
Here's the base class:
struct IDataIO { virtual void Write(const std::string& str) = 0; virtual void Read(char* buffer, std::size_t size) = 0; }; typedef boost::shared_ptr<IDataIO> IDataIOPtr;
A sample subclass:
struct SerialDataIO : IDataIO { void Write(const std::string&) { std::cout << __FUNCTION__ << std::endl; } void Read(char*, std::size_t) { std::cout << __FUNCTION__ << std::endl; } };
Here's the wrapper class that inherits from nondynamic:
struct DataIO : IDataIO, private nondynamic { DataIO(IDataIOPtr dataIO) : mDataIO(dataIO) {}
void Write(const std::string& str) { mDataIO->Write(str); } void Read(char* buffer, std::size_t size) { mDataIO->Read(buffer, size); }
private:
IDataIOPtr mDataIO; };
And finally, the factory: DataIO CreateDataIO(int i) { if( i==0 ) return IDataIOPtr(new SerialDataIO); else throw std::runtime_error("Could not create DataIO"); }
Now the clients of the class hierarchy uses the wrapper, and are completely isolated from pointers:
DataIO dataIO = CreateDataIO(0); dataIO.Write("Hello"); char buffer[1024]; dataIO.Read(buffer, sizeof(buffer));
It should be impossible to misuse DataIO. What do you think about nondynamic? Is it implemented correctly? Named appropriately? Useful at all? Any comments gladly accepted :-)
Thanks in advance!
-- Daniel _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
participants (2)
-
Daniel Lidström
-
Ovanes Markarian