|
Boost Users : |
From: Daniel Lidström (daniel.lidstrom_at_[hidden])
Date: 2008-03-28 05:40:05
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 list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net