CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 15 of 15
  1. #1
    Join Date
    Jan 2005
    Location
    Akron, Ohio
    Posts
    669

    const vector<vector<int> > ??

    I'd like to define a constant global integer array 3 x N (N is known at compile time, just not off the top of my head), but I'm shying away from using standard arrays, such as int[3][N], since you can drop off the edge of them when not careful. I'm thinking about using vector<vector<int> >, but I'm having some noobie trouble initializing it. Can anyone give me some pointers to how I might define a constant global vector and initialize it in, say, GlobalVariables.h file?

    For starters, I've tried:
    vector<int> tempvec;
    tempvec.push_back( /*Number of integers*/ 1);
    tempvec.push_back( /*Number of doubles*/ 0);
    tempvec.push_back( /*Number of booleans*/ 0);
    static const vector<int> NUMBERS_IN_STONE(tempvec);

    . . . but that doesn't work, presumably because it's in an .h file.

    I'd like to find something like:
    static const vector<vector<int> > YeOlNeverChangingNumbers( ??initialization list?? ) and plop that into the .h file, but I can't find anything that works.

    Is there a better strategy that I might take?

    I'm basically looking for a constant global array with some border-patrol built in. Thanks guys.

  2. #2
    Join Date
    Feb 2003
    Posts
    377

    Re: const vector<vector<int> > ??

    The vector class is a good way to go, although you can fall off the edge of a vector also. Here is an example of a two dimensional vector with 3 rows and 8 columns (I'm just randomly choosing N = 8, you can fill in whatever number):
    Code:
    std::vector<std::vector<int> > vec(3, std::vector<int>(8, -1));
    That code initializes all 24 elements to -1. You can put whatever value you want there, and if you leave out the -1 then it will default to 0.

    If you want different values for each row, then you will need some sort of initialization routine to do it. One option is keeping track of whether the vector was initialized and the first time you use it call the initialization method. Another option is to encapsulate it into a class and make a global instance of the class instead of the vector itself, that way the constructor can initialize each row separately. Yet another option is to have three separate vectors. All these options assume you want to initialize with different values, otherwise the code above will be fine.

  3. #3
    Join Date
    Jan 2005
    Location
    Akron, Ohio
    Posts
    669

    Re: const vector<vector<int> > ??

    I seem to be having trouble getting a global vector to work, period. I have the following in a GlobalVariables.h file:

    Code:
    extern vector<int> globalvec;
    and the definition in GlobalVariables.cpp file:

    Code:
    #include <vector>
    using namespace std;
    
    vector<int> globalvec;
    globalvec.push_back(1);
    globalvec.push_back(0);
    globalvec.push_back(0);
    But when I compile it, I get the following errors . . .
    error C2143: syntax error : missing ';' before '.'
    error C2501: 'globalvec' : missing storage-class or type specifiers
    error C2371: 'globalvec' : redefinition; different basic types
    see declaration of 'globalvec'

    I don't see how it could have been redefined. I didn't #include GlobalVariables.h into GlobalVariables.cpp. The whole point of GlobalVariables.h is to #include it elsewhere to let everything else know that globalvec exists. It turns out, if I write:

    Code:
    vector<int> anyname;
    anyname.push_back(1);
    anyname.push_back(0);
    anyname.push_back(0);
    I get the same relative error messages.

    What is going on here? Isn't there any easy way to declare a global variable??

  4. #4
    Join Date
    Feb 2003
    Posts
    377

    Re: const vector<vector<int> > ??

    One problem is that you are calling push_back outside of a function. You can't just have code lying around by itself. The declaration and definition of the vector are ok, and it is ok to use a constructor when you define the global variable, but if you want to call a member function you have to do it inside some other function. That is why I suggested an initialization routine of some sort - either a standalone function that you call at the beginning of the program, or a class that encapsulates the vector and initializes it in a constructor, or some other method of pushing back the data.

    Since you want it to be const (which I didn't notice until now) you can write a function that makes a non-const vector on the stack with the data you want, then use that to initialize the const global vector. Or you could use a regular C style array to initialize the vector. An example of the first idea:
    Code:
    vector<vector<int> > CreateInitialVector()
    {
        vector<int> temp;
        temp.push_back(1);
        temp.push_back(2);
        temp.push_back(0);
        temp.push_back(6);
        return vector<vector<int> >(3, temp);
    }
    
    vector<vector<int> > globalVec = CreateInitialVector();

  5. #5
    Join Date
    Jan 2005
    Location
    Akron, Ohio
    Posts
    669

    Re: const vector<vector<int> > ??

    Hmmm. I wasn't aware that you had to have it in a function, and that does clear up some confusion. Thank you for the info. I'll get to work on it.

  6. #6
    Join Date
    Jan 2005
    Location
    Akron, Ohio
    Posts
    669

    Re: const vector<vector<int> > ??

    I still can't seem to cover my goal here.

    What I'd like to find is a way to define a static const container member of a class in the following way:

    Code:
    const container_type<int> MyClass::MyClassContainer =
    {
    { 3, 8, 2},
    {4, 9 ,2}
    }
    It seems like static members have to be initialized all in one go, which makes it difficult to push_back anything into a vector.

    The other option is to declare a const static integer array, which is easily initialized as above, and then declare two other const static integers: NUMBER_OF_COLUMNS and NUMBER_OF_ROWS. This starts to make things particularly messy, and creates supreme chaos in my program if NUMBER_OF_ROWS doesn't actually match the number of rows, (and the same for columns). I'm particularly worried about some witless programmer coming along and not being aware of this problem . . . like, say, me in a year. I can testify that I'm thoroughly witless afterall.

    So, if there is indeed no means of intializing some type of container as above and I am forced to go by this second route, is there some way I can package it into a nice little macro that the compiler can unpackage as necessary? An example might be:

    CREATE_ARRAY_INITIALIZATION(MyClass, MyClassContainer, { { 3, 8, 2}, {4, 9 ,2} })

    If designed correctly, the macro can count the number of rows and columns, thereby making sure that NUMBER_OF_ROWS and NUMBER_OF_COLUMNS is correct and circumventing the fact that I am completely witless.

    It should be pointed out that I'm looking for a macro that does not physically replace the above notation with code; the macro should encourage the compiler to interpret the notation as the equivalent appropriate code. Is that possible??

    Any sort of idea would be much appreciated! Thanks!

  7. #7
    Join Date
    Feb 2005
    Location
    Normandy in France
    Posts
    4,590

    Re: const vector<vector<int> > ??

    I tried to do it, but i encountered a problem : when initializing static data, there can only be one implicit size.
    For example:
    Code:
    int data[][]={{1,2,3},{4,5,6}}; // compilation error
    Here is an example of what could be done:
    Code:
    #include <vector>
    #include <iostream>
    
    
    		
    template <class T>
    class VectorOfVector:public std::vector<std::vector<T> >
    	{
    	public:
    	typedef typename std::vector<std::vector<T> >::size_type size_type;
    	void ConstructVectorOfVector(const T *data,size_type cLines,size_type cColumns);
    	
    	template <std::size_t cLines,std::size_t cColumns>
    	VectorOfVector<T>(const T (&data)[cLines][cColumns])
    		{
    		ConstructVectorOfVector(&data[0][0],cLines,cColumns);
    		}
    	};
    	
    template <class T>
    void VectorOfVector<T>::ConstructVectorOfVector(const T *data,size_type cLines,size_type cColumns)
    	{
    	resize(cLines);
    	for(typename std::vector<std::vector<T> >::iterator itLines=begin(),itLinesEnd=end(); itLines!=itLinesEnd ; ++itLines)
    		{
    		std::vector<T> &Line=*itLines;
    		Line.reserve(cColumns);
    		for(size_type j=0;j<cColumns;++j)
    			Line.push_back(*data++);
    		}
    	}
    	
    int array[][3]={{1,2,3},{4,5,6}}; // the number of columns must be explicited !
    const VectorOfVector<int> vec(array);
    
    int main()
    	{
    	std::cout<<vec.size()<<" "<<vec[0].size();
    	}
    That is why, for now, i see one solution : doing a function which converts a string such as : "{ {3,8,2}, {4,9,2} }" to the corresponding matrix.

    The main problem, is that this string may use much memory, if the data array is huge.
    But in that case, it is acceptable to put the data in a file, or in the executable's resources section.
    "inherit to be reused by code that uses the base class, not to reuse base class code", Sutter and Alexandrescu, C++ Coding Standards.
    Club of lovers of the C++ typecasts cute syntax: Only recorded member.

    Out of memory happens! Handle it properly!
    Say no to g_new()!

  8. #8
    Join Date
    Jan 2005
    Location
    Akron, Ohio
    Posts
    669

    Re: const vector<vector<int> > ??

    I couldn't get that to compile.

    Here are the errors I got:

    error C2265: '<Unknown>' : reference to a zero-sized array is illegal
    see reference to class template instantiation 'VectorOfVector<T>' being compiled
    error C2265: '<Unknown>' : reference to a zero-sized array is illegal
    see reference to class template instantiation 'VectorOfVector<int>' being compiled
    error C2087: '<Unknown>' : missing subscript
    see reference to class template instantiation 'VectorOfVector<int>' being compiled
    error C2664: '__thiscall VectorOfVector<int>::VectorOfVector<int>(const class VectorOfVector<int> &)' : cannot convert parameter 1 from 'const int [2][3]' to 'const class VectorOfVector<int> &'
    Reason: cannot convert from 'const int [2][3]' to 'const class VectorOfVector<int>'
    No constructor could take the source type, or constructor overload resolution was ambiguous
    warning C4508: 'main' : function should return a value; 'void' return type assumed
    Error executing cl.exe.

    Also, the compiler didn't recognize std:size_t. I switched it to size_type. Is that what you meant? Those errors are a little over my head.

  9. #9
    Join Date
    Oct 2002
    Location
    Singapore
    Posts
    3,128

    Re: const vector<vector<int> > ??

    Are you trying to do something like what Superkoko has shown? You can't do that because the compiler doesn't support that.

    Code:
    const int data[][]={{1,2,3},{4,5,6}}; // compilation error
    As for the "const std::vector<int>" route, it isn't working either because when declaring it const, the compiler doesn't allow you to call non-const member function, like insert().

    The only way to declare a const 2D array is to specify the size.

    Code:
    const int data[][3]={{1,2,3},{4,5,6}}; // This works.
    quoted from C++ Coding Standards:

    KISS (Keep It Simple Software):
    Correct is better than fast. Simple is better than complex. Clear is better than cute. Safe is better than insecure.

    Avoid magic number:
    Programming isn't magic, so don't incant it.

  10. #10
    Join Date
    Feb 2005
    Location
    Normandy in France
    Posts
    4,590

    Re: const vector<vector<int> > ??

    Here is a piece of code that may help you:
    Code:
    #include <vector>
    #include <stdexcep>
    #include <iostream>
    #define USE_STRINGSTREAM
    
    #ifdef USE_STRINGSTREAM
    #include <sstream>
    #else
    #include <strstrea>
    #endif
    
    #define USE_COMMA
    
    template <class T,class TChar=char> // T must be streamable
    class StreamableVector:public std::vector<T>
    	{
    	public:
    	typedef typename std::vector<T>::size_type size_type;
    	
    	typedef TChar char_type;
    	typedef const TChar *string_type;
    	
    	StreamableVector(string_type InitializationString);
    	StreamableVector() {}
    	};
    
    template <class T,class TChar>
    std::basic_istream<TChar> &operator >>(std::basic_istream<TChar> &is,StreamableVector<T,TChar> &vec)
    	{
    	vec.resize(0);
    	char ch;
    	//int eof=std::char_traits<TChar>::eof();
    	
    	if (!(is>>ch)) return is; // read the '{' character!
    	if (ch!='{')
    		{
    		is.putback(ch);
    		is.setstate(std::basic_ios<TChar>::failbit);
    		return is;
    		}
    	
    	#ifdef USE_COMMA
    		bool FirstLoop=true;
    	#endif
    	while(is>>ch)
    		{
    		// at this point we need to find a datum or '}' (if we are in the first loop only).
    		#ifdef USE_COMMA
    			if (FirstLoop && ch=='}') return is; // for the second loop or next loops, at this point, we just read a comma, so we must not test for '}', but instead, read the datum.
    			FirstLoop=false;
    		#else
    			if (ch=='}') return is;
    		#endif
    		
    		is.putback(ch); // at this point, we must read a datum.
    		vec.push_back(T());
    		if (!(is>>vec[vec.size()-1]))
    			{
    			is.setstate(std::basic_ios<TChar>::failbit);
    			return is;
    			}
    		#ifdef USE_COMMA
    		// now we must find a ',' or a '}'
    		if (!(is>>ch)) return is;
    		if (ch=='}') return is;
    		if (ch!=',')
    			{
    			is.putback(ch);
    			is.setstate(std::basic_ios<TChar>::failbit);
    			}
    		#endif
    		} // at this point : a comma has just been read
    	return is;
    	}
    template <class T,class TChar>
    std::basic_ostream<TChar> &operator <<(std::basic_ostream<TChar> &os,const StreamableVector<T,TChar> &vec)
    	{
    	typename StreamableVector<T,TChar>::const_iterator it=vec.begin(),itEnd=vec.end();
    	
    	if (it==itEnd) {os<<"{}";return os;}
    	os<<'{';
    	os<<*it;
    	++it;
    	
    	for(;it!=itEnd;++it)
    		{
    		os<<
    		#ifdef USE_COMMA
    			", "
    		#else
    			' '
    		#endif
    		<<*it;
    		}
    	os<<'}';
    	return os;
    	}
    
    
    static std::string initialization_error_string="invalid_StreamableVector_initialization";
    class invalid_StreamableVector_initialization:public std::runtime_error
    	{
    	public:
    	invalid_StreamableVector_initialization()
    		:std::runtime_error(initialization_error_string) {}
    	};
    	
    template<class T,class TChar>
    StreamableVector<T,TChar>::StreamableVector(const TChar *InitializationString)
    	{
    	#ifdef USE_STRINGSTREAM
    	std::basic_istringstream<TChar> is(InitializationString);
    	#else
    	std::istrstream is(InitializationString);
    	#endif
    	is>>(*this);
    	if (!is.good()) throw invalid_StreamableVector_initialization();
    	}
    	
    
    #ifdef USE_COMMA
    StreamableVector< StreamableVector<std::string> > sv("{ { 4 , 2 , 3 } , { 6 , 8 , 7 }, { 12 , 24 , 475 } }");
    #else
    StreamableVector< StreamableVector<std::string> > sv("{ { 4 2 3 } { 6 8 7 } { 12 24 475 } }");
    #endif
    
    int main()
    	{
    	std::cout<<sv;
    	std::cout<<std::endl;
    	return 0;
    	}
    "inherit to be reused by code that uses the base class, not to reuse base class code", Sutter and Alexandrescu, C++ Coding Standards.
    Club of lovers of the C++ typecasts cute syntax: Only recorded member.

    Out of memory happens! Handle it properly!
    Say no to g_new()!

  11. #11
    Join Date
    Jan 2005
    Location
    Akron, Ohio
    Posts
    669

    Re: const vector<vector<int> > ??

    Well, let's examine the possibility of using a string. What would happen to the string if one of the values was a #define? For example,

    #define MYCLASSA_CONSTANT 5
    string tempstring = "{ MYCLASSA_CONSTANT, 3, 9 }";

    would the compiler interpret this as:

    string tempstring = "{ 5, 3, 9 }";

    ???

    Hmmmm...... Alternately, I COULD pass the address of an array to a class, within which the class would read values until it hit a specifically defined value, like -1. It could use that value to indicate that it has arrived at the end of the array:

    int array[] = { 3, 9, 3, 2, -1};

    This array would be interpretted by the class as having 4 entries. All the values of the array (incidently) are positive, so this appears to be a valid solution. That way, I would not have to specifically state how many entries are in the array, reducing the number of possible errors. I think I'll try that.

  12. #12
    Join Date
    Oct 2002
    Location
    Singapore
    Posts
    3,128

    Re: const vector<vector<int> > ??

    For 1D array, it can be much easier without having to specify -1 for terminating the array. In other words, there is no need for writing a loop to find the size since it can be retrieved during compile-time.

    Code:
    int array[] = { 3, 9, 3, 2};
    int size = sizeof(array)/sizeof(array[0]);
    quoted from C++ Coding Standards:

    KISS (Keep It Simple Software):
    Correct is better than fast. Simple is better than complex. Clear is better than cute. Safe is better than insecure.

    Avoid magic number:
    Programming isn't magic, so don't incant it.

  13. #13
    Join Date
    Jan 2005
    Location
    Akron, Ohio
    Posts
    669

    Re: const vector<vector<int> > ??

    I completely forgot about sizeof(). I'm not sure sure it will work after passing the array to a function though. . .

    Code:
    void myfunction(const int* numbers)
    {
         .....
         sizeof(*numbers)/sizeof(numbers[0]);  //??  Do I have the right syntax?
    }

  14. #14
    Join Date
    Oct 2002
    Location
    Singapore
    Posts
    3,128

    Re: const vector<vector<int> > ??

    No, it doesn't work across different scopes. A workaround is to pass the size over to the other function.

    Code:
    void myfunction(const int *numbers, int size)
    {
    //...
    }
    quoted from C++ Coding Standards:

    KISS (Keep It Simple Software):
    Correct is better than fast. Simple is better than complex. Clear is better than cute. Safe is better than insecure.

    Avoid magic number:
    Programming isn't magic, so don't incant it.

  15. #15
    Join Date
    Jan 2005
    Location
    Akron, Ohio
    Posts
    669

    Re: const vector<vector<int> > ??

    that was sorta why I decided to append negative -1 to the end of the array, so I didn't have to specifically define the size and pass it separately, as per some magic number.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured