Why is std::string and std::vector not being passed to my constructor how I would expect? [duplicate]
Why is std::string and std::vector not being passed to my constructor how I would expect? [duplicate]
This question already has an answer here:
This is my error when trying to compile:
Undefined symbols for architecture x86_64:
"Model::Model(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::vector<int, std::__1::allocator<int> >)", referenced from: ____C_A_T_C_H____T_E_S_T____4() in tests.cpp.o
I have read that std::string is a typedef of std::basic_string and I'm guess that std::vector is a typedef of... std::vector and std::allocator? or something...
Anyway. I have a Settings class that holds my settings and a Model class that contains my model. The code I am attempting to run is as below, and I am unable to compile it. the issue is with it not recognising my model constructor.
Settings s = Settings("../config/settings.json");
std::string mf = s.get_model_file();
std::vector<int> vec = s.get_input_shape();
Model m = Model(mf, vec);
For reference here is my Model class header:
class Model {
public:
Model(std::string model_file, std::vector<int> input_shape);
~Model();
double* get_ref_to_input_buffer();
std::string predict();
private:
std::string _model_file;
fdeep::model _model;
fdeep::shape3 _input_shape;
int _input_size;
double* _input_buffer;
fdeep::tensor3s _result;
void _load_model();
void _set_input_size(std::vector<int> input_shape);
void _set_input_shape(std::vector<int> input_shape);
void _create_input_buffer();
std::string _result_to_string();
};
and my Model class constructor:
Model::Model(std::string model_file, std::vector<int> input_shape) {
_model_file = model_file;
_load_model();
_set_input_size(input_shape);
_set_input_shape(input_shape);
}
These are the function being called in the constructor:
void Model::_load_model() { _model = fdeep::load_model(_model_file); }
void Model::_set_input_size(std::vector<int> input_shape) {
int total = 1;
for (std::vector<int>::iterator it = input_shape.begin();
it != input_shape.end(); ++it) {
total *= *it;
}
_input_size = total;
}
void Model::_set_input_shape(std::vector<int> input_shape) {
_input_shape = fdeep::shape3(input_shape[0], input_shape[1], input_shape[2]);
}
If anyone could point out where I'm going wrong or send me in the direction of what I need to read / learn that would be great. Thank you!
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
Model
_model
: _model(fdeep::load_model(model_file)
Yours is probably a configuration error. You don't link the object file that implements your constructor.
– StoryTeller
Jul 2 at 9:35
Side note:
std::vector
is just an ordinary template - with default template arguments, though, but there are no typedef
s involved.– Aconcagua
Jul 2 at 9:37
std::vector
typedef
@IvanRubinson since C++17 those two codes are the same
– M.M
Jul 2 at 9:39
@KevinGlasson Just another hint that the linker is not provided the object file the constructor resides in... You should add the complete compiler and linker calls to the question as the error is most likely made there...
– Aconcagua
Jul 2 at 10:14
2 Answers
2
According to http://www.cplusplus.com/forum/general/55587/
"Undefined Symbols" generally indicates a linking issue. Are you definitely linking correctly to the appropriate library?
Your code compiles fine. The linker then goes looking in the libraries for the right functions, and since you compiled for architecture x86_64, it looks for the right libraries, similarly compiled - and finds none. This suggests (unless you've simply forgotten to link to the 64 bit library) that you've got a 32 bit version of the library. Your choices are:
cplusplus.com is a poor reference site. It would be better to refer to (in this order): the standard, another question on this site, or cppreference.com
– M.M
Jul 2 at 9:38
I know, but it's the first thing a quick googling showed.
– Ivan Rubinson
Jul 2 at 9:39
google is even lower on that list :P
– M.M
Jul 2 at 9:41
I dont think this is the correct answer. There seems to be an issue with constructor definition.
– mfromla
Jul 2 at 9:52
There is no "appropriate library" that needs to be linked to, the undefined reference refers to the
Model::Model(std::string model_file, std::vector<int> input_shape)
constructor. So the problem is not linking to Model.cpp
(or whatever the file is that defined the constructor), not some library.– Jonathan Wakely
Jul 2 at 10:50
Model::Model(std::string model_file, std::vector<int> input_shape)
Model.cpp
By taking @Aconcagua 's advice I output the linker command from cmake using:
make tests VERBOSE=1
make tests VERBOSE=1
which gave me:
usr/bin/g++ -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/tests.dir/tests.cpp.o CMakeFiles/tests.dir/__/Settings.cpp.o -o ../../../bin/tests
usr/bin/g++ -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/tests.dir/tests.cpp.o CMakeFiles/tests.dir/__/Settings.cpp.o -o ../../../bin/tests
Noticing that this did not have a Model.cpp.o
file I checked CMakeLists.txt and found:
Model.cpp.o
add_executable(tests tests.cpp ../Settings.cpp ../Model.hpp)
add_executable(tests tests.cpp ../Settings.cpp ../Model.hpp)
Note that for Model I have entered the header file not the source file. Changing it to this:
add_executable(tests tests.cpp ../Settings.cpp ../Model.cpp)
add_executable(tests tests.cpp ../Settings.cpp ../Model.cpp)
Fixed my problem.
Right. The linker error was telling you the constructor was not defined. Since you did write that constructor (it's the
Model::Model(std::string model_file, std::vector<int> input_shape)
one that you showed us) then the problem is that you never told the linker to use the file containing that code. If the linker tells you there's an undefined reference, either you forgot to define it, or you forgot to tell the linker where to find it.– Jonathan Wakely
Jul 2 at 10:52
Model::Model(std::string model_file, std::vector<int> input_shape)
Yeah so I was thrown off by my general lack of knowledge! and confusion over the typedef expansion of my parameters
– Kevin Glasson
Jul 2 at 10:58
Yes, interpreting linker errors like that should become second nature when you're more familiar with C++ (and the ways a build can fail). It doesn't help that the "true names" of the types as printed by the linker don't match the names you used for them in the source code, but you did actually interpret that part correctly :-)
– Jonathan Wakely
Jul 2 at 11:05
class
Model
doesn't inherit the_model
class in its declaration and you define the constructor and call the base constructor in it.: _model(fdeep::load_model(model_file)
– user3366592
Jul 2 at 9:25