Jump to content
  • Advertisement
Sign in to follow this  
dead1ock

Odd "disappearance" of std::vector items.

This topic is 3298 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Im having a problem with items "disappearing" from my vector. I have a class called "ByteBuffer" which will take variables and serialize them in byte form to a std::vector. However, for some reason, all the items in the vector disappear after writing them. That said, I did find out that if I write and read from the ByteBuffer in the same function, it works. This lead me to believe that it had something to do with the scope. However, my ByteBuffer variable for my CppUnit test is a private member of a class, so its on the heap and always in scope until the object is deleted. But, when I try to read and write from the same buffer, separating the reading from writing into separate test functions, it asserts saying im trying to read indexes that do not exist. ByteBuffer.h
#ifndef BYTEBUFFER_H
#define BYTEBUFFER_H

// PROJECT INCLUDES
//
#include <framework/util/endian.h>
#include <framework/util/ogdef.h>
#include <framework/util/ogtypes.h>

// STL INCLUDES
//
#include <assert.h>
#include <vector>

/**
 * @class ByteBuffer
 * @brief
 */
class ByteBuffer
{
public:
	ByteBuffer() : mReadIndex(0), mWriteIndex(0) { mStorage.reserve( DEFAULT_RESERVE ); }
	ByteBuffer( size_t res ) : mReadIndex(0), mWriteIndex(0) { mStorage.reserve( res ); }
	~ByteBuffer() { }

	const static uint32 DEFAULT_RESERVE = 512;

	// OPERATIONS
	//
	void Clear() { mStorage.clear(); mReadIndex = mWriteIndex = 0; }

	// OPERATORS
	//
	template< typename T > inline ByteBuffer& operator << ( T& value )
	{
		if( mWriteIndex + sizeof(T) > mStorage.capacity() )
			assert( 0 && "Trying to write more then the ByteBuffer will hold!" );

		EndianConvert( value );

		mStorage.resize( mWriteIndex + sizeof(T) );
		memcpy( &mStorage[mWriteIndex], (void*) &value, sizeof(T) );

		mWriteIndex += sizeof(T);
		return *this;
	}

	template< typename T > inline ByteBuffer& operator >> ( T& value )
	{
		if( mReadIndex + sizeof(T) > mStorage.size() )
			assert( 0 && "Trying to read more then the ByteBuffer has!" );

		memcpy( (void*) &value, &mStorage[mReadIndex], sizeof(T) );
		EndianConvert( value );
		mReadIndex += sizeof(T);
		return *this;
	}

	// ACCESS
	//
	uint32 Size() const { return mStorage.size(); }
	uint32 Capacity() const { return mStorage.capacity(); }

	// INQUIRES
	//
	bool Empty() const { return mStorage.empty(); }

protected:
private:
	uint32						mReadIndex;
	uint32						mWriteIndex;
	std::vector<uint8>			mStorage;

};

TestByteBuffer.h
#ifndef TESTBYTEBUFFER_H
#define TESTBYTEBUFFER_H

// CPPUNIT INCLUDES
//
#include <cppunit/extensions/HelperMacros.h>

// PROJECT INCLUDES
//
#include <framework/util/bytebuffer.h>

class TestByteBuffer : public CppUnit::TestFixture
{
	CPPUNIT_TEST_SUITE( TestByteBuffer );
	CPPUNIT_TEST( TestWrite_BasicTypes );
	CPPUNIT_TEST( TestRead_BasicTypes );
	CPPUNIT_TEST( TestClear );
	CPPUNIT_TEST_SUITE_END();

public:
	TestByteBuffer( void );
	~TestByteBuffer( void );

	void setUp( void );
	void tearDown( void );

	void TestWrite_BasicTypes( void );
	void TestRead_BasicTypes( void );
	void TestClear( void );

protected:
private:
	ByteBuffer			mBuffer;
};

TestByteBuffer.cc
#include "testbytebuffer.h"
#include <assert.h>

CPPUNIT_TEST_SUITE_REGISTRATION( TestByteBuffer );

TestByteBuffer::TestByteBuffer( void )
{
}

TestByteBuffer::~TestByteBuffer( void )
{
}

void
TestByteBuffer::setUp( void )
{
}

void
TestByteBuffer::tearDown( void )
{
}

void
TestByteBuffer::TestWrite_BasicTypes( void )
{
	int8 _sint8 = -255;
	int16 _sint16 = -512;
	int32 _sint32 = -1024;
	int64 _sint64 = -2048;
	uint8 _suint8 = 256;
	uint16 _suint16 = 512;
	uint32 _suint32 = 1024;
	uint64 _suint64 = 2048;
	std::wstring _wstring = (wchar_t*) "Unicode String";
	std::string _string = "Ascii String";

	mBuffer << _sint8;
	mBuffer << _sint16;
	mBuffer << _sint32;
	mBuffer << _sint64;
	mBuffer << _suint8;
	mBuffer << _suint16;
	mBuffer << _suint32;
	mBuffer << _suint64;
	mBuffer << _wstring;
	mBuffer << _string;
}

void
TestByteBuffer::TestRead_BasicTypes( void )
{
	int8 _sint8 = 0;
	int16 _sint16 = 0;
	int32 _sint32 = 0;
	int64 _sint64 = 0;
	uint8 _suint8 = 0;
	uint16 _suint16 = 0;
	uint32 _suint32 = 0;
	uint64 _suint64 = 0;
	std::wstring _wstring = (wchar_t*) "NULL";
	std::string _string = "NULL";

// The problem occurs here.
// However, if I was to move this entire function up the TestWrite_BasicTypes
// it would work properly.
	mBuffer >> _sint8;
	mBuffer >> _sint16;
	mBuffer >> _sint32;
	mBuffer >> _sint64;
	mBuffer >> _suint8;
	mBuffer >> _suint16;
	mBuffer >> _suint32;
	mBuffer >> _suint64;
	mBuffer >> _wstring;
	mBuffer >> _string;

}

void TestByteBuffer::TestClear( void )
{
	mBuffer.Clear();

	if( mBuffer.Size() > 0 )
		assert( 0 && "Buffer was more than the size of 0 after a Clear()." );
}

Thanks, Dead1ock

Share this post


Link to post
Share on other sites
Advertisement
The problem is unrelated to the use of std::vector or the design of your class - it's got to do with the way CppUnit executes tests. Each test is run on a totally different instance of your fixture class, so when it goes to run you TestWrite_BasicTypes test, it creates an instance of the TestByteBuffer class, executes the TestWrite_BasicTypes method then destroys that copy of the TestByteBuffer class. Then, it creates a whole new instance of the TestByteBuffer class and calls the TestRead_BasicTypes method. Obviously, since this is a new instance of the class, it's a new ByteBuffer.

When writing unit tests, you need to make sure that each individual test is totally self-contained. That is, a test shouldn't depend on previous tests having been run. Creating a new instance of the test fixture class for each test is how CppUnit tries to enforce (if that's the right word) that concept.

Share this post


Link to post
Share on other sites
Quote:
Original post by Codeka
The problem is unrelated to the use of std::vector or the design of your class - it's got to do with the way CppUnit executes tests. Each test is run on a totally different instance of your fixture class, so when it goes to run you TestWrite_BasicTypes test, it creates an instance of the TestByteBuffer class, executes the TestWrite_BasicTypes method then destroys that copy of the TestByteBuffer class. Then, it creates a whole new instance of the TestByteBuffer class and calls the TestRead_BasicTypes method. Obviously, since this is a new instance of the class, it's a new ByteBuffer.

When writing unit tests, you need to make sure that each individual test is totally self-contained. That is, a test shouldn't depend on previous tests having been run. Creating a new instance of the test fixture class for each test is how CppUnit tries to enforce (if that's the right word) that concept.


Ok, thats great to know. I never knew that is how CppUnit executed its tests, because I used to use another Unit Testing framework that did not do this.

Thanks a bunch.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!