I'm trying to create a basic Python interpreter using cpp and I'm facing an unresolved external symbol problem with the container of the _variables: an unordered_map
here is the declaration:
private:
static std::unordered_map<std::string, Type*> _variables;//type is a base class for all the types of variables
and here is the relevant code using the container:
bool Parser::makeAssignment(std::string str)
{
char ch = '=';
int count = 0;
Type* newVar;
for(int i = 0; (i = str.find(ch, i)) != std::string::npos; i )
{
count ;
}
if (count != 1)
{
return false;
}
std::string::size_type pos = str.find('=');
std::string varName = str.substr(0, pos);
std::string varVal = str.substr(pos 1, str.size());
Helper::trim(varName);
Helper::trim(varVal);
if (!isLegalVarName(varName))
{
throw SyntaxException();
}
if (getType(varVal) != NULL)
{
newVar = getType(varVal);
}
else
{
throw SyntaxException();
}//checks if the declaration written is valid
auto it = _variables.find(varName);
if (it != _variables.end())
{
it->second = newVar;
}
else
{
_variables.insert({ varName, newVar });
}
return true;
}
Type* Parser::getVariableValue(std::string str)
{
auto it = _variables.find(str);
if (it != _variables.end())
{
return it->second;
}
return NULL;
}
void Parser::cleanMemory()
{
_variables.clear();
}
I would also appreciate an explanation for this problem in general (LNK2001) because I have encountered it several times before.
CodePudding user response:
This issue has to do with the difference between a declaration and a definition.
A declaration such as
class Parser {
...
static std::unordered_map<std::string, Type*> _variables;
...
};
tells the compiler that a symbol Parser::_variables
will be available with the given type.
All code modules (.cpp
files) which use that symbol will include the header file with the declaration to make the symbol known to that module.
In one place (only), the symbol needs to be defined, i.e. instantiated such that it is actually present in the final binary. Hence one .cpp
file should have a definition like this:
std::unordered_map<std::string, Type*> Parser::_variables;
Building of a program is, put shortly, a two-step process: compilation and linking.
During compilation, the binary translation of each code module is generated except for unresolved "external" references to symbols (functions and variables) that are used (declared), but not defined in that module.
During the linking step, all the modules are put together and unresolved references in each module are resolved by pointing to the module where they are defined. If it turns out that there is a symbol which is used, but not defined anywhere, then that reference remains unresolved and the final binary cannot be generated. Thus, the linker reports the observed error "unresolved external symbol".