std::map and std::string incompatibility?

Started by
11 comments, last by Bregma 13 years ago
Hi,

I want to store string-objects in a map object - map<string, int> m_Strings. However every time I do this:

string str = "Test";

map<string, int>::iterator result;

result = m_Strings.find(str);

if(result == m_Strings.end())
{}


d:\programme\microsoft visual studio 10.0\vc\include\xfunctional(125): error C2784: "bool std::operator <(const std::vector<_Ty,_Ax> &,const std::vector<_Ty,_Ax> &)": template-Argument für "const std::vector<_Ty,_Ax> &" konnte nicht von "const std::string" hergeleitet werden.

In english it should be something like template-argument for ... can't be derived from ... .

Does anyone know whats wrong here? Are map and string simply incompatible? although I think I have seen code where string has been stored in a map. I have to use string for storing btw. because I need to create LPCSTR dynamically on runtime, and the only method to store such strings safely is std::string, to my knowledge.. or am I wrong?
Advertisement
This should work. Is it possible that m_Strings is const at the point of your test??
I'm skeptical that m_Strings is of the type std::map<std::string, int>; why is the error message mentioning std::vector?
Chess is played by three people. Two people play the game; the third provides moral support for the pawns. The object of the game is to kill your opponent by flinging captured pieces at his head. Since the only piece that can be killed is a pawn, the two armies agree to meet in a pawn-infested area (or even a pawn shop) and kill as many pawns as possible in the crossfire. If the game goes on for an hour, one player may legally attempt to gouge out the other player's eyes with his King.
This should work. Is it possible that m_Strings is const at the point of your test?? [/quote]

At least not intentionally, here is the code:

LPDIRECT3DTEXTURE9 CResources::GetTexture(LPCSTR lpTextureName)
{
map<string, LPDIRECT3DTEXTURE9>::iterator result;

string str = lpTextureName;

result = m_MapTextures.find(str);

if(result == m_MapTextures.end())
{
AddTexture(lpTextureName);
return GetTexture(lpTextureName);
}

return result->second;
}


I didn't declare str as a constant, so it shouldn't be one, or am I mistaken?

I'm skeptical that m_Strings is of the type std::map<std::string, int>; why is the error message mentioning std::vector? [/quote]

Well, now that you say it, thats really strange, but m_Strings surely is a map. Its defined as: map<string, LPDIRECT3DTEXTURE9> m_MapTextures;

If you really wanna know, here is the whole code of the class:

#pragma once

#include <map>
#include <d3d9.h>
#include <d3dx9.h>

using namespace std;

class CResources
{
public:
CResources(void);
virtual ~CResources(void);

void Init(LPDIRECT3DDEVICE9 lpDevice);

LPDIRECT3DTEXTURE9 GetTexture(LPCSTR lpTextureName);

protected:

LPDIRECT3DDEVICE9 m_lpDevice;

void AddTexture(LPCSTR lpFileName);

map<string, LPDIRECT3DTEXTURE9> m_MapTextures;


};


#include "Resources.h"

CResources::CResources(void)
{
}

CResources::~CResources(void)
{
for(map<string, LPDIRECT3DTEXTURE9>::iterator ii=m_MapTextures.begin();ii!=m_MapTextures.end();++ii)
{
ii->second->Release();
}
m_MapTextures.clear();
}

void CResources::Init(LPDIRECT3DDEVICE9 lpDevice)
{
m_lpDevice = lpDevice;
}

LPDIRECT3DTEXTURE9 CResources::GetTexture(LPCSTR lpTextureName)
{
map<string, LPDIRECT3DTEXTURE9>::iterator result;

string str = lpTextureName;
result = m_MapTextures.find(str);

if(result == m_MapTextures.end())
{
AddTexture(lpTextureName);
return GetTexture(lpTextureName);
}

return result->second;
}

void CResources::AddTexture(LPCSTR lpFileName)
{
LPDIRECT3DTEXTURE9 lpTexture;

D3DXIMAGE_INFO ImageInfo;

D3DXGetImageInfoFromFile(lpFileName, &ImageInfo);

D3DXCreateTextureFromFileEx(m_lpDevice, lpFileName, ImageInfo.Width, ImageInfo.Height, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_FILTER_NONE, D3DX_FILTER_NONE, 0, 0, 0, &lpTexture);

string str = lpFileName;
m_MapTextures[str] = lpTexture;
}


Anything obviously wrong with this?
I can't see anything obviously wrong with it, other than that I don't see a #include <string> anywhere.
Chess is played by three people. Two people play the game; the third provides moral support for the pawns. The object of the game is to kill your opponent by flinging captured pieces at his head. Since the only piece that can be killed is a pawn, the two armies agree to meet in a pawn-infested area (or even a pawn shop) and kill as many pawns as possible in the crossfire. If the game goes on for an hour, one player may legally attempt to gouge out the other player's eyes with his King.
I can't see anything obviously wrong with it, other than that I don't see a #include <string> anywhere. [/quote]

I just wanted to slap myself in the face.. thats just it! There where a few more includes of some other classes of me in that code, I thought string was included anywhere in these headers. Thanks anyway, problem solved!

At least not intentionally, here is the code: [...]

Anything obviously wrong with this?


Nothing do with your problem (which I see you've already solved), but your constructor should at the very least initialize m_lpDevice to a null pointer and not just leave it pointing at some random address. What would be even better is if you could ditch your Init() method and pass lpDevice in the constructor ... that's what constructors are for after all.
Also, that m_MapTextures.clear(); call in your destructor is pointless. This happens implicitly when the map is destroyed.

Next:


map<string, LPDIRECT3DTEXTURE9>::iterator result;
result = m_MapTextures.find(str);


Why not just


const map<string, LPDIRECT3DTEXTURE9>::iterator result = m_MapTextures.find(str);


?

When ever possible, you should make declarations double over as initializations. That way you can often make variables const (as in the example above since you didn't have to change result after initializing it), which helps readability and makes it easier to reason about existing code (for instance when one of your colleages has to understand code that you wrote).

Next issue, D3DXGetImageInfoFromFile() and D3DXCreateTextureFromFileEx Function() both have return values, and the reason they do so is not so you can be a lazy coder and just ignore them. Both of these functions can fail and the way to check for that is to inspect their return values. You should never just assume that a function will probably work if the documentation says that it can fail. Check the return value and if it denotes failure, do something about it ... throw an exception, bring up a message box or at least write an error message to a log file.

EDIT: How did I forget my favorite issue?? :lol:

You should make your class uncopyable by declaring a private copy constructor and a private copy assignment operator and implementing neither. Because otherwise you'll get the compiler default copy constructor / copy assignment operator, which would just copy your instance bit by bit, and the way your class is implemented, that would result in disaster when your destructor runs.

Nothing do with your problem (which I see you've already solved), but your constructor should at the very least initialize m_lpDevice to a null pointer and not just leave it pointing at some random address.


[s]As a member, it's default-constructed to the null pointer.[/s]
[TheUnbeliever]

As a member, it's default-constructed to the null pointer.


Did I miss something? It's a typedef for a raw pointer and unlike what some languages might do, I am VERY sure C++ doesn't "default construct" anything unless it has a default constructor which is not the case for primitive types.
f@dzhttp://festini.device-zero.de
Use map<string, int>::const_iterator!

This topic is closed to new replies.

Advertisement