mix placement new with a standard delete

  • Follow


Is it legal to mix placement new with a standard delete operation?  I'm
curious about the following test case:

#include <memory>
#include <stdexcept>
#include <cassert>

template
<
	typename T // requires trivial constructor/destructor
>
class storage
{
	private:
		// construct:
		explicit storage(int size)
			: m_Size(size)
		{
		}

		// copy:
		storage(const storage&); // noncopyable

		// assign:
		storage& operator = (const storage&); // nonassignable

	public:
		// destroy:
		~storage()
		{
		}

		// methods:
		static std::auto_ptr<storage> create(int size)
		{
			void *memory =
				operator new
				(
					sizeof(storage)
					+ (size - 1) * sizeof(T)
				);

			std::auto_ptr<storage> result
				(
					new(memory) storage(size)
				);

			return result;
		}

		int size() const
		{
			return m_Size;
		}

		// operators:
		T& operator [] (int index)
		{
			if((0 <= index) && (index < m_Size))
			{
				return m_Data[index];
			}
			else
			{
				assert(false && "Invalid index");
				throw std::logic_error("Invalid index");
			}
		}

		const T& operator [] (int index) const
		{
			if((0 <= index) && (index < m_Size))
			{
				return m_Data[index];
			}
			else
			{
				assert(false && "Invalid index");
				throw std::logic_error("Invalid index");
			}
		}

	private:
		// members:
		const int m_Size;
		T m_Data[1 /*m_Size*/];
};

int main()
{
	std::auto_ptr< storage<int> > s1(storage<int>::create(512));
	std::auto_ptr< storage<int> > s2(storage<int>::create(1024));
	std::auto_ptr< storage<int> > s3(storage<int>::create(2048));

	return 0;
}

--- news://freenews.netfront.net/ - complaints: news@netfront.net ---


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Mike 3/24/2011 7:58:13 AM

On 24.03.2011 14:58, Mike Kelley wrote:
>
> Is it legal to mix placement new with a standard delete operation?

This depends... There is no general answer. Since there is no placement
delete you can call manually, the regular delete operator must be used
anyhow in case you use the "placement new" as a "new from a memory
pool", and an overloaded delete operator releases the memory back to the
memory pool. So the question is not really whether it is "legal", but
how you obtained the memory, and whether your memory release - operator
delete - fits to the method the memory has been allocated.

> I'm
> curious about the following test case:
>

> // methods:
> static std::auto_ptr<storage> create(int size)
> {
> void *memory =
> operator new
> (
> sizeof(storage)
> + (size - 1) * sizeof(T)
> );
>
> std::auto_ptr<storage> result
> (
> new(memory) storage(size)
> );
>
> return result;
> }

Note further that, while you're allocating memory sufficient to store
"storage", you never construct the "T" objects which remain thus
uninitialized (anything may happen).


> // operators:
> T& operator [] (int index)
> {
> if((0 <= index) && (index < m_Size))
> {
> return m_Data[index];

See above. m_Data remains unitialized, partially, and what happens with
the out-of bounds access - after all, you lied to the compiler in
defining only one, but not n elements - remains open. A compiler *may*
add bounds checking to your code, after all.

Running into the operator delete with this class then, however, seems
comparably harmless. After all, since the compiler can only pass the
pointer to the object, and not its size, it must have stored the size
elsewhere, when invoking operator new, to have it available when
releasing memory, and you're allocating and releasing the memory from
the same memory pool.

However, the issue with unitialized members remains. I wonder, why not
try valarray, or allocate the memory for the arrays "conservatively"
with operator []? Or what about using a vector, as the simplest
solution? IOW, which problem do you want to solve?

Greetings,

Thomas


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Thomas 3/25/2011 3:08:29 AM


On Mar 24, 2:58 pm, Mike Kelley <mckelle...@gmail.com> wrote:
> Is it legal to mix placement new with a standard delete operation?

I think so (compilers seem to agree), but should not be done. If you
overload new, you better have equivalent overload of delete. Consider:

class test
{
//...
test() { if (problem) throw some_exception; }
void* operator new(size_t, void* p) { return p; }
};

void* p = getmem();
auto_ptr<test> ptest(new (p) test);

If "problem" indeed happens, there is no matching operator delete of
the correct type to possibly free memory. For that, "test" needs

 void operator delete(void* p, void*) { ::delete p; }

BTW, without that corresponding "delete", e.g. comeau warns:

Test::operator new(size_t, void *)" has
         no corresponding operator delete (to be called if an
exception is
         thrown during initialization of an allocated object)

Of course, you are required to match allocation/deallocation in your
new/delete overloads.

Goran.


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Goran 3/25/2011 10:04:09 AM

2 Replies
295 Views

(page loaded in 0.065 seconds)

Similiar Articles:













7/23/2012 1:45:34 AM


Reply: