Jan 192009

It’s quite easy to read the contents of a file to a vector at one go. For this we need to get the size of a file and ask vector to allocate a buffer to hold these many bytes (use vector::resize()). Here is a function which does this. Note that it’s a byte/char vector.

#include "vector"
#include "fstream"

void ReadFileToVector( const char* FileName, std::vector<char>& FileBuff )
   using namespace std;

   ifstream ifile;
   ifile.open( FileName, ios::in );

   // Get file size
   ifile.seekg(0, ios_base::end);
   streamoff FileSize = ifile.tellg();
   ifile.seekg(0, ios_base::beg);

   // Resize vector to file size
   FileBuff.resize( FileSize, 0 );
   // Read in file contents to buffer
   ifile.read(&FileBuff[0], FileSize);

Benefit of using a vector instead of a char pointer is that we don’t have to do memory management and also we are directly accessing this buffer so no reallocations occur internally but we’ll have to check for allocation failure after calling vector::resize since files can be of huge sizes. You can optimize this further, post a comment if you find any issue/optimization. Also note that there are other ways to achieve the same behavior for e.g. using istream_iterator and back_inserter but this does cause frequent reallocations in a vector IMO making things slower.

Aug 272008

Use std::vector::max_size() function.

Don’t confuse this function with std::vector::capacity() and std::vector::size() functions. vector::capacity() tells us when a vector will be reallocated and vector::size() tells us the count of elements inserted into a vector.

Source code of vector::max_size looks like this…

_SIZT max_size() const _THROW0()
   // estimate maximum array size
   _SIZT _Count = (_SIZT)(-1) / sizeof (_Ty);
   return (0 < _Count ? _Count : 1);

-1 is being cast to _SIZT and then divided by the sizeof the vector type. Have a look at the following illustration...

&#91;sourcecode language='cpp'&#93;template<class T>
void PrintVectorMaxSize( std::vector<t>& Obj)
   const std::vector</t><t>::size_type MaxSize = Obj.max_size();
   std::cout < < "Max elements that can be inserted into a vector having elements of size '" << sizeof( T )
             << "' is: " << MaxSize << std::endl;

int main()
   PrintVectorMaxSize( std::vector<byte>() );
   PrintVectorMaxSize( std::vector<int>() );
   PrintVectorMaxSize( std::vector<double>() );
   PrintVectorMaxSize( std::vector<char *>() );

Here is the output for the above program…

Max elements that can be inserted into a vector having elements of size ‘1’ is: 4294967295
Max elements that can be inserted into a vector having elements of size ‘4’ is: 1073741823
Max elements that can be inserted into a vector having elements of size ‘8’ is: 536870911
Max elements that can be inserted into a vector having elements of size ‘4’ is: 1073741823

PS: Please edit those html tags inserted by code formatter before compilation.

Technorati Tags: , , , , , , ,

Aug 022008

Is it possible to do this with just one line of code? Oh yes!

Have a look…

typedef int VT;
typedef std::vector VTVec;

void Dump( VTVec& VecToPrint, std::ostream& stream, const char* lpszMsg )
// We will be wrapping every element within a square bracket.
// In the end output looks like this… [123] [864] [
stream << lpszMsg << "["; // Get iterator for given stream, every element will be seperated with second // parameter. std::ostream_iterator Itr( stream, "] [" ); // Just one line to dump vector contents, no loops needed std::copy( VecToPrint.begin(), VecToPrint.end(), Itr ); // Remove redundant space and bracket ( " [" ) from the end // After this statement the series will look like [123] [864] stream << "\b\b \b\b\n"; }// End Dump int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) { VTVec VecObj( 10000, 0 ); // Fill vector with random number, see earlier post on std::generate std::generate( VecObj.begin(), VecObj.end(), rand ); // Dump to std::cout Dump( VecObj, std::cout, "Dumping vector of ints...\n" ); }// End _tmain[/sourcecode]

Aug 022008

Let us suppose that you want to fill out a vector with 10000 random elements, phew. Hmm so what you would do is to write a for loop, iterate through, and fill out the elements.

Well I can do it with just one line of code. 🙂 Look

// Typedefs
typedef int VtElem;
typedef std::vector<vtelem> Vector;
const Vector::size_type Size = 10000;

Vector VecObj( Size );
// Look at the last parameter, it needs a callback function pointer/function object/functor,
// we've given standard c "rand" function to fill out vector with random elements.
std::generate( VecObj.begin(), VecObj.end(), rand );

So now we have a vector that has been randomly been filled out. We can replace rand with any kind of filling in method. You can even have a vector full of prime numbers using a prime functor.

There is another version of std::generate called std::generate_n, which as the name suggests generates upto n elements.

Looks like this…

// Fill just 10 elements with random numbers
std::generate_n( VecObj.begin(), 10, rand );

Aug 022008

There are 8 constructors for std::vector class, out of which there is this constructor that takes two parameters…

vector( size_type _Count,  const Type& _Val );

First parameter is size of the vector, second is default value for all elements in the vector.

Let’s suppose you have 1000 Employees in your organization each of them has an initial salary of Rs 8000, we would like to maintain information related to them using a vector. This is how we will be declaring the vector object and initializing every Employee element in it to to have an initial salary of 8000.

class Employee
       Employee() : m_Salary( 0 )
       explicit Employee( const int Salary ) : m_Salary( Salary )
       int m_Salary;
};// End class Employee

// Typedefs
typedef Employee Emp;
typedef std::vector<emp> EmpVector;

// 1000 employees with salary member variable of every employee instance in
// our vector initialized to 8000
EmpVector EmpVecObj( 1000, Employee( 8000 ));

Jul 302008

So what does std::transform function do?

“Applies a specified function object to each element in a source range or to a pair of elements from two source ranges and copies the return values of the function object into a destination range.”

Some general applications of using transform is as follows…

  1. For doing some kind of operation on two vectors of same type and storing the result in a third vector.
  2. For doing some kind of in place operations on a vector.

So simplified prototypes of this function…

template<class InputIterator, class OutputIterator, class UnaryFunction>
OutputIterator transform( InputIterator _First1,
                          InputIterator _Last1,
                          OutputIterator _Result,
                          UnaryFunction _Func );
template</class><class InputIterator1, class InputIterator2, class OutputIterator, class BinaryFunction>
OutputIterator transform( InputIterator1 _First1,
                          InputIterator1 _Last1,
                          InputIterator2 _First2,
                          OutputIterator _Result,
                          BinaryFunction _Func );

So first prototype can take two different vectors or can be the same vector for inplace modification,while second one takes three, two source vectors (for e.g. two vector of ints and we add these two vectors and place the result in a third vector).

The applications of this function is powerful! Here are some demos

// Starts here
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
   void Demo_Std_TransformInplace();

   void Demo_Std_Transform_Binary();

   return 0;

#include <vector> // for std::vector
#include <algorithm> // for std::transform

// Callbacks used with std::transform, can also be functors but for ease of calling //
// Unary operations. Note that I am alternating 'class' and 'typename' keywords just
// to prevent code formatting errors in HTML.
template<class T> T Square( const T Elem ) { return Elem * Elem; }
template<typename T> T ReverseSign( const T Elem ) { return -Elem; }
template<class T> T IncrementBy1( const T Elem ) { return Elem + 1; }
template<typename T> T DecrementBy1( const T Elem ) { return Elem - 1; }

// Binary operations
template<class T> T Add( const T Elem1, const T Elem2 ) { return Elem1 + Elem2; }
template<typename T> T Multiply( const T Elem1, const T Elem2 ) { return Elem1 * Elem2; }
template<class T> T Divide( const T Elem1, const T Elem2 ) { return Elem1 / Elem2; }
template<typename T> T Substract( const T Elem1, const T Elem2 ) { return Elem1 - Elem2; }

// A typedef for ease of use
typedef double VectorType; // Change this type and see the result
typedef std::vector<vectortype> VTVector; // Vector typedef
const VTVector::size_type Size = 1000; // Default size, increase to test performance

// Randomly fills in a vector
void FillInIntVector( VTVector& Vec )
   for( VTVector::size_type Index = 0; Index < Vec.size(); ++Index )
      Vec&#91;Index&#93; = static_cast<vectorType>( rand() );

// Functions for testing std::transform, Debug through and see the results //
void Demo_Std_TransformInplace()
   VTVector VTObj( Size );
   FillInIntVector( VTObj );

   // Do some in place operations
   std::transform( VTObj.begin(), VTObj.end(), VTObj.begin(), Square</vectortype><vectortype> );
   std::transform( VTObj.begin(), VTObj.end(), VTObj.begin(), ReverseSign</vectortype><vectortype> );
   std::transform( VTObj.begin(), VTObj.end(), VTObj.begin(), IncrementBy1</vectortype><vectortype> );
   std::transform( VTObj.begin(), VTObj.end(), VTObj.begin(), DecrementBy1</vectortype><vectortype> );

void Demo_Std_Transform_Binary()
   // Randomly fill in first vector
   VTVector VTObj1( Size );
   FillInIntVector( VTObj1 );  

   // Randomly fill in second vector
   VTVector VTObj2( Size );
   FillInIntVector( VTObj2 );

   // Added result will be placed in here
   VTVector Result( Size );

   // Add "VTObj1" and "VTObj2" vector place the result in "Result"
   std::transform( VTObj1.begin(), VTObj1.end(), VTObj2.begin(), Result.begin(), Add</vectortype><vectortype> );
   std::transform( VTObj1.begin(), VTObj1.end(), VTObj2.begin(), Result.begin(), Multiply</vectortype><vectortype> );  
   std::transform( VTObj1.begin(), VTObj1.end(), VTObj2.begin(), Result.begin(), Divide</vectortype><vectortype> );
   std::transform( VTObj1.begin(), VTObj1.end(), VTObj2.begin(), Result.begin(), Substract</vectortype><vectortype> );