Sign in to follow this  
Rasmadrak

std::vector and template problem...

Recommended Posts

Hi, I'm curious why the following doesn't work.
template <class T>      //do I need to define T somewhere?
class ResourceManager
{
    private:
        vector<T*> *items;

    public:
    
    void init()
    {
        items = new vector<T*>;

        for (vector<T*>::iterator i = items->begin(); i != items->end(); i++) //<-- This is not accepted, "Expected ; before i" 
        {
          //...  do stuff
        }
    }
}

To me it should work, but this is my first attempt using templates, so I might be missing something. I also have the same problem with std::map. Thanks for your time! /Robert

Share this post


Link to post
Share on other sites
You should be more specific than just saying "it doesnt work"... [EDIT] - ahh, I see you described the error in your comments, never mind!

Anyway, you need a semicolon on the end of your class definition, and you need "std::" in front of "vector". This works for me:
template <class T>
class ResourceManager
{
private:
std::vector<T*> *items;

public:

void init()
{
items = new std::vector<T*>;

for (std::vector<T*>::iterator i = items->begin(); i != items->end(); i++)
{
//... do stuff
}
}
};






[EDIT]
As for style:

1) Dont use init functions! Use constructors and destructors:

template <class T>

class ResourceManager
{
private:
std::vector<T*> *items;
public:
ResourceManager()
{
items = new std::vector<T*>;

for (std::vector<T*>::iterator i = items->begin(); i != items->end(); i++)
{
//... do stuff
}
}
~ResourceManager()
{
delete items;
}
};





2) Is there any reason that items is a pointer?:

template <class T>

class ResourceManager
{
private:
std::vector<T*> items;
public:
ResourceManager()
{
for (std::vector<T*>::iterator i = items.begin(); i != items.end(); i++)
{
//... do stuff
}
}
};



Share this post


Link to post
Share on other sites
The compiler is not certain that std::vector<T*>::iterator is actually referring to a type in this case — as far as it's concerned, it has as much chance of being a type as it does a member.

Just give it a hint that it's a type:

for ( typename std::vector< T* >::iterator i = ... )

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
You're probably missing a typename keyword

typename vector<T*>::iterator


Serves me right for wandering away before posting.

Share this post


Link to post
Share on other sites
Hi!

"typename vector<T*>::iterator" did the trick!

I just noticed that I've left out quite a bit of information, for instance:
In my code I do have a semicolon after the class declaration, and "using namespace std". I also create and delete "items" in the constructor/destructor.
I guess I shouldn't post before going to sleep! :)

Also, about "items" being a pointer - I've read somewhere that the memory used when dynamically allocating variables is faster than putting it on the stack, so that's why. :)

Much appreciated, thanks again!

/Robert

Share this post


Link to post
Share on other sites
Quote:
Original post by Rasmadrak

Also, about "items" being a pointer - I've read somewhere that the memory used when dynamically allocating variables is faster than putting it on the stack, so that's why. :)

It's the contrary : putting/removing variables on the stack is faster that allocating/deallocating memory for them on the heap, unless you've written a damned good allocator for your types.

Share this post


Link to post
Share on other sites
Quote:
Original post by rolkA
Quote:
Original post by Rasmadrak

Also, about "items" being a pointer - I've read somewhere that the memory used when dynamically allocating variables is faster than putting it on the stack, so that's why. :)

It's the contrary : putting/removing variables on the stack is faster that allocating/deallocating memory for them on the heap, unless you've written a damned good allocator for your types.


And, regardless, std::vector stores elements dynamically, anyway, so why not just let it serve the purpose it's meant to (i.e. be a resizeable array that looks after its own memory) rather than abusing it?

Share this post


Link to post
Share on other sites
Quote:
Original post by TheUnbeliever
Quote:
Original post by rolkA
Quote:
Original post by Rasmadrak

Also, about "items" being a pointer - I've read somewhere that the memory used when dynamically allocating variables is faster than putting it on the stack, so that's why. :)

It's the contrary : putting/removing variables on the stack is faster that allocating/deallocating memory for them on the heap, unless you've written a damned good allocator for your types.


And, regardless, std::vector stores elements dynamically, anyway, so why not just let it serve the purpose it's meant to (i.e. be a resizeable array that looks after its own memory) rather than abusing it?


And, regardless that, the std::vector object will not necessarily be on the stack — it will be in the same storage as the enclosing ResourceManager-type object (i.e., if you do new ResourceManager then the vector will be allocated in the free store even without newing it manually).

Furthermore, and most importantly — you wouldn’t notice the difference anyway. Unless your algorithm were terribly wrong — in which case your performance bottleneck would be the algorithm and not your allocation method. So, to reiterate the Golden Rule — do not optimise prematurely.

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
You're probably missing a typename keyword

typename vector<T*>::iterator


Could someone explain why this needs to be typename'd? I'm not completely familiar with typenames, and I would have written this same for loop (without a typename) and would have had the same problem. Why doesn't that work just as an iterator for the for loop?

Share this post


Link to post
Share on other sites
Inside template definitions, there are two kinds of types: dependent types and non-dependent types. Dependent types depend on the template arguments. So if you had a template with a T type argument then T would be a dependent type, but std::vector<T> is also a dependent type because it depends on what the definition of T is. Examples of non-dependent types would be like int, char or pretty much anything that doesn't contain T.

When using the :: operator on a dependent type, the compiler is supposed to assume that the identifier is a non-type identifier like a static member variable or member function name. So std::vector<T>::iterator will be assumed to be a non-type. In order for iterator to be treated as a type, you need to specify the typename keyword.

Share this post


Link to post
Share on other sites
Quote:
Original post by Shakedown
Quote:
Original post by SiCrane
You're probably missing a typename keyword

typename vector<T*>::iterator


Could someone explain why this needs to be typename'd? I'm not completely familiar with typenames, and I would have written this same for loop (without a typename) and would have had the same problem. Why doesn't that work just as an iterator for the for loop?


Because in the expression vector<T>::iterator, T is a template parameter — that means, vector<T> is not really a type, it is a template from which a type will be generated. So the compiler can’t know what vector<T>::iterator will be at the moment it processes the enclosing class template — in which case it defaults to considering iterator a member object. This then causes a syntax error as the compiler sees for (someVariable it = ... ). By giving the typename there, you tell the compiler it should treat the symbol iterator as a type, rather than an object.

This typename stuff is one of the things that take a while to get, but the general (and inaccurate) rule is: When you do something like SomeType<T>::SomeNestedType, where T is a template parameter, you need to use typename there.

Share this post


Link to post
Share on other sites
Quote:
Original post by Oxyd
Because in the expression vector<T>::iterator, T is a template parameter — that means, vector<T> is not really a type, it is a template from which a type will be generated.

Close, but not quite. vector<T> is unambiguously a type, and by itself needs no typename.

Share this post


Link to post
Share on other sites
Quote:
Original post by Rasmadrak
In my code I do have a semicolon after the class declaration, and "using namespace std".

That is a bad idea.

Your ResourceManager class is a template class, so I'm safe to assume, that it is defined in a header file.

Having "using namespace std" in a header file is a bad idea, because every source file that include the header, will also include the "using namespace std", which isn't always desired. So, just to be safe, I would suggest to explicitly add "std::" everywhere, instead of "using namespace std" in a header file.

Just a tip. ;)

Share this post


Link to post
Share on other sites
You can use "using namespace std;" inside of functions also. That
whey you don't need to type "std::" everywhere, any you don't get the
nasty defined in header file side effect.

Share this post


Link to post
Share on other sites
Quote:
Original post by mzeo77
You can use "using namespace std;" inside of functions also.

Would this insert std:: at compile time or would there be any kind of overhead at runtime?

Quote:
Original post by Oxyd
And, regardless that, the std::vector object will not necessarily be on the stack — it will be in the same storage as the enclosing ResourceManager-type object (i.e., if you do new ResourceManager then the vector will be allocated in the free store even without newing it manually).

I didn't know that! I guess not using pointers inside the class would increase performance as well if a lot of new/delete is going on, would it not?

Paulius Maruska:
I'll remove the namespace as soon as I convert my resourcemanager into a class of it's own. Currently it's under development and currently labeled a "pet project" :)

Thanks again all!

Share this post


Link to post
Share on other sites
Quote:
Original post by Rasmadrak
Quote:
Original post by mzeo77
You can use "using namespace std;" inside of functions also.

Would this insert std:: at compile time or would there be any kind of overhead at runtime?

It only affects visibility of the symbols — and symbols are entirely compile-time thing. It will not have any impact on runtime at all.

Quote:
Original post by Rasmadrak
I didn't know that! I guess not using pointers inside the class would increase performance as well if a lot of new/delete is going on, would it not?

new and delete are quite costly operations, yes.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this