The following code compiles and runs successfully on OS X using Xcode 6.3.2. However, it crashes when run on Windows using VS2013.
#include <vector>
#include <string>
#include <memory>
#include <functional>
#include <iostream>
void validate(const std::string& name,
int value,
std::vector<std::string>& values)
{
std::cout << "name: " << name << " value: " << value << "\n";
}
struct Property
{
public:
Property(const std::string& name,
const std::function<void(const std::string&, int)>& validationFunction) :
m_name(name),
m_validationFunction(validationFunction)
{
}
const std::string m_name;
const std::function<void(const std::string&, int)> m_validationFunction;
};
const std::vector<std::shared_ptr<Property>> properties
{
{
std::make_shared<Property>("identifier1",
[](const std::string& name, int value)
{
validate(name, value, std::vector<std::string>{"foo"});
})
},
{
std::make_shared<Property>("identifier2",
std::bind(validate,
std::placeholders::_1,
std::placeholders::_2,
std::vector<std::string>{"bar"}))
}
};
int main()
{
properties[0]->m_validationFunction(properties[0]->m_name, 4);
properties[1]->m_validationFunction(properties[1]->m_name, 5);
return 0;
}
The reason for the crash is that the first element in properties appears to be corrupt. When I inspect the memory I see this:
properties { size=2 } std::vector<std::shared_ptr<Property>,std::allocator<std::shared_ptr<Property> > >
[size] 2 int
[capacity] 2 int
[0] shared_ptr {m_name=<Error reading characters of string.> m_validationFunction={...} } [4277075694 strong refs, 4277075693 weak refs] [{_Uses=4277075694 _Weaks=4277075694 }] std::shared_ptr<Property>
[1] shared_ptr {m_name="identifier2" m_validationFunction=bind(0x011315a5 {schema-init.exe!validate(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,int,class std::vector<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > > &)}, (_1, _2, { size=1 })) } [1 strong ref] [make_shared] std::shared_ptr<Property>
[Raw View] 0x0115295c {schema-init.exe!std::vector<std::shared_ptr<Property>,std::allocator<std::shared_ptr<Property> > > properties} {...} std::vector<std::shared_ptr<Property>,std::allocator<std::shared_ptr<Property> > > *
If I replace std::bind with a direct call to validate as for the first element in properties then the code executes successfully.
Can someone explain what I'm doing wrong.
I noted Paul R's comment above that he successfully ran the code using VC2013 so I updated my copy of Visual Studio 2013 (update 5) and the code now runs ok. So I guess it was a compiler bug.
Related
I am trying to reuse a parser (named parser1_rule) that I have isolated in a translation unit (unit1.h/unit1.cpp), into another parser (name trace_parser). However I get a warning and an error message (reproduced and reformated below for easier reading) stating more or less (this is my interpretation) that parser1_rule have not been defined (or instantiated) for the new context trace_context_t.
Indeed, in X3, rules have two template parameters: iterators and context. I thought when mixing two rules, one had to make sure they both use the same context and iterator's types. So I paid attention to use the same context for parser1_rule and trace_parser : context_type. The same goes for the iterator, as recalled in X3: Linker Error (unresolved external symbol “parse_rule”) on nonterminal parser
But it seams this is not the way to go ? Shall I move the rule's definitions into an hpp file (which I wish I can avoid).
I created a minimal reproducible example to help understanding the issue:
EDIT: boost 1.71.0 and Visual Studio 16.8.2
unit1.h
#ifndef UNIT1_H
#define UNIT1_H
#include <cstdint>
#include "boost/spirit/home/x3.hpp"
#include "boost/spirit/include/support_istream_iterator.hpp"
namespace x3 = boost::spirit::x3;
using iter_t = boost::spirit::istream_iterator;
using context_t = x3::phrase_parse_context<x3::ascii::space_type>::type;
using parser1_t = x3::rule<class p1, std::uint64_t>;
BOOST_SPIRIT_DECLARE(parser1_t);
parser1_t const & ATparser();
#endif /* UNIT1_H */
unit1.cpp
#include "unit1.h"
parser1_t const parser1 = "parser1_rule";
auto const parser1_def = x3::lexeme[x3::lit("AT") >> x3::uint_];
BOOST_SPIRIT_DEFINE(parser1);
BOOST_SPIRIT_INSTANTIATE(parser1_t, iter_t, context_t);
parser1_t const& ATparser() { return parser1; }
Source.h
#ifndef SOURCE_H
#define SOURCE_H
#include <cstdint>
#include "boost/spirit/home/x3.hpp"
#include "boost/spirit/include/support_istream_iterator.hpp"
namespace x3 = boost::spirit::x3;
namespace trace {
using trace_parser_tag = struct trace_parser;
using rule_type = x3::rule<trace_parser_tag>;
BOOST_SPIRIT_DECLARE(rule_type);
}
trace::rule_type const& trace_parser();
#endif
Source.cpp
#include <iostream>
#include <fstream>
#include "unit1.h"
#include "Source.h"
namespace x3 = boost::spirit::x3;
/** reading:
Trace address: AT123434 */
namespace trace {
rule_type const tr = "trace_parser";
auto fill = [](auto& ctx) {}; /* semantic action to break automatic attribute propagation (first step) */
auto const tr_def = ("Trace address: " >> ATparser())[fill];
BOOST_SPIRIT_DEFINE(tr);
BOOST_SPIRIT_INSTANTIATE(rule_type,iter_t,context_t)
}
trace::rule_type const& trace_parser() {
return trace::tr;
}
int main(int argc, char* argv[])
{
std::string input("Trace address: AT123434");
std::ifstream i(input);
std::cout << "parsing: " << input << "\n";
boost::spirit::istream_iterator b(i >> std::noskipws);
boost::spirit::istream_iterator e = {};
bool v = x3::phrase_parse(b, e, trace_parser(), x3::ascii::space);
std::cout << "result: " << (v ? "OK" : "Failed") << "\n";
return v;
}
compilation output
1>Source.cpp
1>H:\X\XXXXX\unit1.h(26,1): warning C5046: 'parse_rule': Symbol involving type with internal linkage not defined
1>Source.obj : error LNK2019: unresolved external symbol "bool __cdecl parse_rule<class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> >,struct boost::spirit::x3::context<struct trace::trace_parser,struct boost::spirit::x3::action<struct boost::spirit::x3::sequence<struct boost::spirit::x3::literal_string<char const *,struct boost::spirit::char_encoding::standard,struct boost::spirit::x3::unused_type>,struct boost::spirit::x3::rule<class p1,unsigned __int64,0> >,class <lambda_bca3e58e86871d1e58f1a6062ad05fd2> > const ,struct boost::spirit::x3::context<struct boost::spirit::x3::skipper_tag,struct boost::spirit::x3::char_class<struct boost::spirit::char_encoding::ascii,struct boost::spirit::x3::space_tag> const ,struct boost::spirit::x3::unused_type> > >(struct boost::spirit::x3::rule<class p1,unsigned __int64,0>,class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> > &,class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> > const &,struct boost::spirit::x3::context<struct trace::trace_parser,struct boost::spirit::x3::action<struct boost::spirit::x3::sequence<struct boost::spirit::x3::literal_string<char const *,struct boost::spirit::char_encoding::standard,struct boost::spirit::x3::unused_type>,struct boost::spirit::x3::rule<class p1,unsigned __int64,0> >,class <lambda_bca3e58e86871d1e58f1a6062ad05fd2> > const ,struct boost::spirit::x3::context<struct boost::spirit::x3::skipper_tag,struct boost::spirit::x3::char_class<struct boost::spirit::char_encoding::ascii,struct boost::spirit::x3::space_tag> const ,struct boost::spirit::x3::unused_type> > const &,unsigned __int64 &)" [...cut...] referenced in function "public: bool __cdecl boost::spirit::x3::rule<class p1,unsigned __int64,0>::parse<class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> >,struct boost::spirit::x3::context<struct trace::trace_parser,struct boost::spirit::x3::action<struct boost::spirit::x3::sequence<struct boost::spirit::x3::literal_string<char const *,struct boost::spirit::char_encoding::standard,struct boost::spirit::x3::unused_type>,struct boost::spirit::x3::rule<class p1,unsigned __int64,0> >,class <lambda_bca3e58e86871d1e58f1a6062ad05fd2> > const ,struct boost::spirit::x3::context<struct boost::spirit::x3::skipper_tag,struct boost::spirit::x3::char_class<struct boost::spirit::char_encoding::ascii,struct boost::spirit::x3::space_tag> const ,struct boost::spirit::x3::unused_type> >,unsigned __int64>(class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> > &,class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> > const &,struct boost::spirit::x3::context<struct trace::trace_parser,struct boost::spirit::x3::action<struct boost::spirit::x3::sequence<struct boost::spirit::x3::literal_string<char const *,struct boost::spirit::char_encoding::standard,struct boost::spirit::x3::unused_type>,struct boost::spirit::x3::rule<class p1,unsigned __int64,0> >,class <lambda_bca3e58e86871d1e58f1a6062ad05fd2> > const ,struct boost::spirit::x3::context<struct boost::spirit::x3::skipper_tag,struct boost::spirit::x3::char_class<struct boost::spirit::char_encoding::ascii,struct boost::spirit::x3::space_tag> const ,struct boost::spirit::x3::unused_type> > const &,struct boost::spirit::x3::unused_type,unsigned __int64 &)const "
Warning:
1>H:\X\XXXXX\unit1.h(26,1): warning C5046: 'parse_rule': Symbol involving type with internal linkage not defined
Error message:
unresolved external symbol:
bool __cdecl parse_rule<iterator_t,trace_context_t>(
parser1_t,
iterator_t &,
iterator_t const &,
trace_context_t const &,
unsigned __int64 &
)
referenced in function
public:
bool __cdecl boost::spirit::x3::rule<class p1,unsigned __int64,0>::parse<
iterator_t, trace_context_t, unsigned __int64>
(
iterator_t &,
iterator_t const &,
trace_context_t const &,
struct boost::spirit::x3::unused_type,
unsigned __int64 &
)const
Assuming the following shorcuts:
using action_t = struct boost::spirit::x3::action<
struct boost::spirit::x3::sequence<
struct boost::spirit::x3::literal_string<
char const *,
struct boost::spirit::char_encoding::standard,
struct boost::spirit::x3::unused_type>,
struct boost::spirit::x3::rule<class p1,unsigned __int64,0>>,
class <lambda_bca3e58e86871d1e58f1a6062ad05fd2>>
using ctxt_t = struct boost::spirit::x3::context<
struct boost::spirit::x3::skipper_tag,
struct boost::spirit::x3::char_class<
struct boost::spirit::char_encoding::ascii,
struct boost::spirit::x3::space_tag> const ,
struct boost::spirit::x3::unused_type>>
using iterator_t = class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> >
using trace_context_t = struct boost::spirit::x3::context<
struct trace::trace_parser,
action_t const ,
ctxt_t>
Move to Boost 1.74.0 solved the issue.
I am a beginner with threads and am trying to write code to extract 20 tags from a file.
The number of files can run up to 7000, so I would like to make good use of a thread-pool.
I use Code::Blocks 20.3 and MinGW 17.1 on a Windows 10 Pro computer.
I have 'borrowed' the thread-pool code from: https://codereview.stackexchange.com/questions/221626/c17-thread-pool
I made a test that MinGW probably handles as C code, and that worked just fine.
My project involves multiple class files with dialog windows, and when I copied the working C code it fails to build. Unfortunately I do not understand how to convert the code from C to C++.
The test code I wrote is below.
The build messages are:
||=== Build: Debug in ThreadPool2 (compiler: GNU GCC Compiler) ===|
Threadpool.h||In instantiation of 'auto Thread_Pool::execute(F, Args&& ...) [with F = TrackTags::TagsStdStrings (TrackTags::*)(std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>); Args = {std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&}]':|
TrackTags.cpp|43|required from here|
Threadpool.h|62|error: no type named 'type' in 'struct std::invoke_result<TrackTags::TagsStdStrings (TrackTags::*)(std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>), std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>'|
Threadpool.h|63|error: no type named 'type' in 'struct std::invoke_result<TrackTags::TagsStdStrings (TrackTags::*)(std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>), std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>'|
Threadpool.h|62|error: no type named 'type' in 'struct std::invoke_result<TrackTags::TagsStdStrings (TrackTags::*)(std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>), std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>'|
Threadpool.h|63|error: no type named 'type' in 'struct std::invoke_result<TrackTags::TagsStdStrings (TrackTags::*)(std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>), std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>'|
TrackTags.cpp||In member function 'void TrackTags::GetMultiStdTags()':|
TrackTags.cpp|43|error: invalid use of void expression|
||=== Build failed: 5 error(s), 2 warning(s) (0 minute(s), 0 second(s)) ===|
the lines with errors are:
TrackTags.cpp
[43] StdFutures.push_back(Pool.execute(GetStdTags, wsFile, wsCol));
Threadpool.h
[62] std::packaged_task<std::invoke_result_t<F, Args...>()> Task_PKG(std::bind(function, args...) );
[63] std::future<std::invoke_result_t<F, Args...>> Future = Task_PKG.get_future();
in Threadpool.h.
I tried:
[43] StdFutures.push_back(Pool.execute(std::mem_fn(TrackTags::GetStdTags), std::ref(wsFile), std::ref(wsCol)));
But this did not help.
I hope someone can help me make this work.
Thank you.
Ruud.
---TrackTags.h---
#ifndef TRACKTAGS_H
#define TRACKTAGS_H
#include "Threadpool.h"
#include <iostream>
#include <sstream>
#include <string>
#include <thread>
#include <vector>
class TrackTags
{
public:
struct TagsStdStrings
{
bool OK;
std::string ThreadID;
std::string FileName;
std::string Collection;
};
public:
TrackTags();
virtual ~TrackTags();
TagsStdStrings GetStdTags(std::string wsFile, std::string wsCollection);
void GetMultiStdTags();
protected:
private:
};
#endif // TRACKTAGS_H
---TrackTags.cpp---
#include "TrackTags.h"
#define _UNICODE
TrackTags::TrackTags()
{
//ctor
}
TrackTags::~TrackTags()
{
//dtor
}
TrackTags::TagsStdStrings TrackTags::GetStdTags(std::string wsFile, std::string wsCollection)
{
TagsStdStrings TagLine;
TagLine.FileName = wsFile;
TagLine.Collection = wsCollection;
TagLine.OK = true;
// Add thread-ID to the structure
auto tid = std::this_thread::get_id();
std::stringstream ssID;
ssID << tid;
std::string sID{ssID.str()};
TagLine.ThreadID = sID;
return TagLine;
}
void TrackTags::GetMultiStdTags()
{
Thread_Pool Pool(1);
std::vector<std::future<TagsStdStrings>> StdFutures;
std::string wsFile{"FileTest"};
std::string wsCol{"ColTest"};
StdFutures.push_back(Pool.execute(GetStdTags, wsFile, wsCol));
for (auto &Fut : StdFutures)
{
TagsStdStrings TSS;
TSS = Fut.get();
if (TSS.OK)
{ std::cout << TSS.ThreadID << "--" << TSS.FileName << "--" << TSS.Collection << std::endl; }
else
{ std::cout << "Empty Tag structure\n"; }
}
}
---Threadpool.h---
#pragma once
#include <condition_variable>
#include <functional> //bind
#include <future> //packaged_task
#include <mutex>
#include <queue>
#include <thread>
#include <type_traits> //invoke_result
#include <vector>
class Thread_Pool
{
public:
Thread_Pool(size_t Thread_Count);
~Thread_Pool();
Thread_Pool(const Thread_Pool &) = delete;
Thread_Pool &operator=(const Thread_Pool &) = delete;
template <typename F, typename ...Args>
auto execute(F, Args&&...);
private:
class Task_Container_Base
{
public:
virtual ~Task_Container_Base() {};
virtual void operator()() = 0;
};
template <typename F>
class Task_Container : public Task_Container_Base
{
public:
Task_Container(F &&Fnc) : f(std::forward<F>(Fnc)) {}
void operator()() override { f(); }
private:
F f;
};
template <typename Func>
static std::unique_ptr<Task_Container_Base> Allocate_Task_Container(Func &&f)
{
return std::unique_ptr<Task_Container_Base>(new Task_Container<Func>(std::forward<Func>(f))
);
}
std::vector<std::thread> Threads;
std::queue<std::unique_ptr<Task_Container_Base>> Tasks;
std::mutex Task_Mutex;
std::condition_variable Task_CV;
bool Stop_Threads = false;
};
template <typename F, typename ...Args>
auto Thread_Pool::execute(F function, Args &&...args)
{
std::unique_lock<std::mutex> Queue_Lock(Task_Mutex, std::defer_lock);
std::packaged_task<std::invoke_result_t<F, Args...>()> Task_PKG(std::bind(function, args...) );
std::future<std::invoke_result_t<F, Args...>> Future = Task_PKG.get_future();
Queue_Lock.lock();
Tasks.emplace(Allocate_Task_Container( [Task(std::move(Task_PKG))]() mutable { Task(); }) );
Queue_Lock.unlock();
Task_CV.notify_one();
return Future;
}
---Threadpool.cpp---
#include "Threadpool.h"
Thread_Pool::Thread_Pool(size_t Thread_Count)
{
for (size_t i = 0; i < Thread_Count; ++i)
{
Threads.emplace_back( std::thread( [&]()
{
std::unique_lock<std::mutex> Queue_Lock(Task_Mutex, std::defer_lock);
while (true)
{
Queue_Lock.lock();
Task_CV.wait( Queue_Lock, [&]() -> bool { return !Tasks.empty() || Stop_Threads; } );
if (Stop_Threads && Tasks.empty()) return;
auto Temp_Task = std::move(Tasks.front());
Tasks.pop();
Queue_Lock.unlock();
(*Temp_Task)();
}
} ) );
}
}
Thread_Pool::~Thread_Pool()
{
Stop_Threads = true;
Task_CV.notify_all();
for (std::thread &Thread : Threads)
{
Thread.join();
}
}
GetStdTags is a non-static member function. You have access to this - the pointer to the object you're calling it on - inside it. Therefore when you call it, you need to specify the object which the member function should be working on.
Pool.execute(GetStdTags, wsFile, wsCol)
Here you only specify the two formal arguments, but not the object for the member function. Passing that along would look like this:
TrackTags one_object; // < yes, ONE, shared between the threads!
// if you don't want to share it between threads,
// you need to create multiple objects (and keep them alive)
Pool.execute(&TrackTags::GetStdTags, &one_object, wsFile, wsCol)
// ^ pointer to member ^ pointer
// function to object,
// "this" inside the
// member function
More information about std::bind and member functions.
However, since your class (TrackTags) doesn't have any data members and the member function GetStdTags doesn't need access to any object of type TrackTags, you can make it a static member function (or even a free function, really) and get by without a TrackTags object.
Thank you Daniel.
The test project seemed to work, so I started on the "real" thing.
It is building without errors, but not working as planned.
I tested with 4 threads and 4 files and ran it twice.
Result below: What did I miss?
B:\Music\FLAC_Unlisted\Adam Baldych\Bridges\01 Adam Baldych - Bridges.flac
B:\Music\FLAC_Unlisted\Adam Baldych\Bridges\02 Adam Baldych - Polesie.flac
B:\Music\FLAC_Unlisted\Adam Baldych\Bridges\03 Adam Baldych - Mosaic.flac
B:\Music\FLAC_Unlisted\Adam Baldych\Bridges\04 Adam Baldych - Riese.flac
6--Riese--Col Test
7--Riese--Col Test
8--Riese--Col Test
9--Riese--Col Test
B:\Music\FLAC_Unlisted\Adam Baldych\Bridges\01 Adam Baldych - Bridges.flac
B:\Music\FLAC_Unlisted\Adam Baldych\Bridges\02 Adam Baldych - Polesie.flac
B:\Music\FLAC_Unlisted\Adam Baldych\Bridges\03 Adam Baldych - Mosaic.flac
B:\Music\FLAC_Unlisted\Adam Baldych\Bridges\04 Adam Baldych - Riese.flac
First run, completes, but with wrong results, and the second run immediately after the first completed hangs.
This is the function called:
TrackTags::TagsStruct TrackTags::GetTags(wxString wsFile, wxString wsCollection)
{
// create Tag variable structure
struct TagsStruct TagLine;
.
.
return TagLine
}
It loads a DLL and extracts the required tags from a file to return it in a structure with the Thread-ID as first item (temporary to check how the code runs).
The calling function is below:
void TrackTags::GetMultiStdTags()
{
wxString wsCol{"Col Test"};
std::vector<wxString> wsTracks
{
"B:\\Music\\FLAC_Unlisted\\Adam Baldych\\Bridges\\01 Adam Baldych - Bridges.flac",
"B:\\Music\\FLAC_Unlisted\\Adam Baldych\\Bridges\\02 Adam Baldych - Polesie.flac",
"B:\\Music\\FLAC_Unlisted\\Adam Baldych\\Bridges\\03 Adam Baldych - Mosaic.flac",
"B:\\Music\\FLAC_Unlisted\\Adam Baldych\\Bridges\\04 Adam Baldych - Riese.flac"
};
TrackTags one_object;
Thread_Pool Pool(4);
std::vector<std::future<TagsStruct>> StdFutures;
for (auto &tr : wsTracks)
{
std::cout << tr << std::endl;
StdFutures.push_back(Pool.execute(&TrackTags::GetTags, &one_object, tr, wsCol));
}
for (auto &Fut : StdFutures)
{
TagsStruct TSS;
TSS = Fut.get();
if (TSS.OK)
{ std::cout << TSS.ThreadID << "--" << TSS.TrackTitle << "--" << TSS.Collection << std::endl; }
else
{ std::cout << "Empty Tag structure found\n"; }
}
}
I've been working with static for quite a long time but now when the header files come I'm a little confused.
The main problem is this code :
#include <iostream>
#include <string>
#include <sstream>
#include <set>
#ifndef WORD_H
#define WORD_H
#include<unordered_map>
class Word
{
private:
std::string word;
int k;
static std::unordered_map<std::string, int> x;
public:
Word(std::string word) : word(word)
{
if (x.find(word) != x.end())
x.insert({ word , 0 });
else
{
x[word]++;
}
}
std::string getWord() const
{
return x.find(this->word)->first;
}
int getCount() const
{
return x.find(this->word)->second;
}
friend bool operator<(const Word& a, const Word& b);
};
bool operator<(const Word& a, const Word& b)
{
return a.getWord() < b.getWord();
}
#endif
std::ostream& operator<<(std::ostream& out, const Word& w) {
return out << w.getWord() << " " << w.getCount();
}
void printWordCounts(const std::string& line) {
std::istringstream lineIn(line);
std::set<Word> words;
std::string wordStr;
while (lineIn >> wordStr) {
words.insert(Word(wordStr));
}
for (Word w : words) {
std::cout << w << std::endl;
}
}
int main() {
std::string line;
std::getline(std::cin, line);
printWordCounts(line);
std::cout << "---" << std::endl;
std::getline(std::cin, line);
printWordCounts(line);
return 0;
}
I know that there is a problem with the static keyword, but what exactly is it?
Also, the error is one of my favourites. Those errors between linker and STL:
Error LNK2001 unresolved external symbol "private: static class std::unordered_map<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,int,struct std::hash<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,struct std::equal_to<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,class std::allocator<struct std::pair<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const ,int> > > Word::x" (?x#Word##0V?$unordered_map#V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##HU?$hash#V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std###2#U?$equal_to#V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std###2#V?$allocator#U?$pair#$$CBV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##H#std###2##std##A) ConsoleApplication63 C:\Users\Ivo\source\repos\ConsoleApplication63\ConsoleApplication63\ConsoleApplication63.obj 1
I hope that someone can give me an explanation.
You have only declared the static member x. You also need to define it outside the class like this:
std::unordered_map<std::string, int> Word::x;
From c++17, you can define x inside the class definition like this:
inline static std::unordered_map<std::string, int> x;
Static variable declarations in classes are identical to declaring a global variable in a header file, except it's 'symbol' lies within the namespace of the class and therefore access to it is protected with visibility levels. This means that like global variable declarations, static class variable declarations have 'weak' linkage and a compilation unit needs to define the symbol definition, so that the linker can tie the memory associated with the variable declarations in other files to exactly one variable.
Defining the static variable is done outside the class like so:
// <variable type> <class type>::<variable name>;
std::unordered_map<std::string, int> Word::x;
Note that only one .cpp file needs to define the variable
I have been trying to figure out what is not linked or declared correctly in my code. I am writing a simple game engine in C++ for learning purposes and am trying to create a state machine. The linker error has something to do with unordered_list, list, or map. I am not sure which. The error is for the constructor with two arguments, which are two typedefs and is included in the code I show, the error happens when I call that constructor.
IState.h
#ifndef ZX_STATE_H
#define ZX_STATE_H
#include "coreDefines.h"
#include "zxstring.h"
ZX_NS_START
class IState
{
tstring pm_name;
public:
const tstring& name();
virtual ~IState() = default;
virtual void Pre() = 0;
virtual void Run() = 0;
virtual void Post() = 0;
};
ZX_NS_END
#endif
IStateMachine.h
#ifndef ZX_ISTATEMACHINE_H
#define ZX_ISTATEMACHINE_H
#include "object.h"
#include "zxstring.h"
#include "IState.h"
#include <unordered_set>
#include <map>
#include <list>
ZX_NS_START
typedef std::map<tstring, IState*> StateMap;
typedef std::unordered_set<tstring> StateSet;
typedef std::list<StateSet> RunOrder;
class IStateMachine : object, IState
{
public:
const tstring defaultState = T("zx default state");
IStateMachine();
IStateMachine(RunOrder** runOrder, StateSet** states);
virtual ~IStateMachine();
void Add(IState* state);
void Remove(IState* state);
private:
StateMap pm_states;
RunOrder** pm_runOrder;
StateSet** pm_activeStates;
void Pre() override;
void Run() override;
void Post() override;
void SetUpDefaultState();
class DefaultState: IState
{
IStateMachine* pm_parent;
public:
DefaultState();
explicit DefaultState(IStateMachine* parent);
void Pre() override;
void Run() override;
void Post() override;
};
};
ZX_NS_END
#endif
IStateMachine.cpp
#include "IStateMachine.h"
USINGZX;
IStateMachine::IStateMachine(): pm_states(StateMap()), pm_runOrder(nullptr), pm_activeStates(nullptr)
{
SetUpDefaultState();
}
IStateMachine::IStateMachine(RunOrder** runOrder, StateSet** states) : pm_states(StateMap()), pm_runOrder(runOrder), pm_activeStates(states)
{
SetUpDefaultState();
}
IStateMachine::~IStateMachine()
{
delete pm_states[defaultState];
}
void IStateMachine::Add(IState* state)
{
pm_states.insert(std::make_pair(state->name(), state));
}
void IStateMachine::Remove(IState* state)
{
pm_states.erase(state->name());
}
void IStateMachine::Pre()
{
pm_states[defaultState]->Pre();
}
void IStateMachine::Run()
{
pm_states[defaultState]->Run();
}
void IStateMachine::Post()
{
pm_states[defaultState]->Post();
}
void IStateMachine::SetUpDefaultState()
{
DefaultState* def = new DefaultState(this);
pm_states.insert(std::make_pair(defaultState, (IState*)def));
}
IStateMachine::DefaultState::DefaultState() :pm_parent(nullptr)
{
}
IStateMachine::DefaultState::DefaultState(IStateMachine* parent): pm_parent(parent)
{
}
void IStateMachine::DefaultState::Pre()
{
for(const auto& states : **pm_parent->pm_runOrder)
{
for(const auto& runState : states)
{
pm_parent->pm_states[runState]->Pre();
}
}
}
void IStateMachine::DefaultState::Run()
{
for(const auto& states: **pm_parent->pm_runOrder)
{
for(const auto& runState : states)
{
pm_parent->pm_states[runState]->Run();
}
}
}
void IStateMachine::DefaultState::Post()
{
for (const auto& states : **pm_parent->pm_runOrder)
{
for (const auto& runState : states)
{
pm_parent->pm_states[runState]->Post();
}
}
}
Here is the long...looong error message
Error LNK2019 unresolved external symbol "public: __thiscall Zx::IStateMachine::IStateMachine(class std::list,class std::allocator >,struct std::hash,class std::allocator > >,struct std::equal_to,class std::allocator > >,class std::allocator,class std::allocator > > >,class std::allocator,class std::allocator >,struct std::hash,class std::allocator > >,struct std::equal_to,class std::allocator > >,class std::allocator,class std::allocator > > > > > * *,class std::unordered_set,class std::allocator >,struct std::hash,class std::allocator > >,struct std::equal_to,class std::allocator > >,class std::allocator,class std::allocator > > > * *)" (??0IStateMachine#Zx##QAE#PAPAV?$list#V?$unordered_set#V?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std##U?$hash#V?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std###2#U?$equal_to#V?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std###2#V?$allocator#V?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std###2##std##V?$allocator#V?$unordered_set#V?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std##U?$hash#V?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std###2#U?$equal_to#V?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std###2#V?$allocator#V?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std###2##std###2##std##PAPAV?$unordered_set#V?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std##U?$hash#V?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std###2#U?$equal_to#V?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std###2#V?$allocator#V?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std###2##3##Z) referenced in function "public: __thiscall TestStateMachine::TestStateMachine(class std::list,class std::allocator >,struct std::hash,class std::allocator > >,struct std::equal_to,class std::allocator > >,class std::allocator,class std::allocator > > >,class std::allocator,class std::allocator >,struct std::hash,class std::allocator > >,struct std::equal_to,class std::allocator > >,class std::allocator,class std::allocator > > > > > * *,class std::unordered_set,class std::allocator >,struct std::hash,class std::allocator > >,struct std::equal_to,class std::allocator > >,class std::allocator,class std::allocator > > > * *)" (??0TestStateMachine##QAE#PAPAV?$list#V?$unordered_set#V?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std##U?$hash#V?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std###2#U?$equal_to#V?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std###2#V?$allocator#V?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std###2##std##V?$allocator#V?$unordered_set#V?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std##U?$hash#V?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std###2#U?$equal_to#V?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std###2#V?$allocator#V?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std###2##std###2##std##PAPAV?$unordered_set#V?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std##U?$hash#V?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std###2#U?$equal_to#V?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std###2#V?$allocator#V?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std###2##2##Z)
I can usually figure these out pretty easily but for what ever reason this one is stumping me.(Maybe something to do with the unreadable type in the error message)
I don't believe this will be of any consequence, however, here is the test code that invokes the linker error
StateMachineTest.cpp
class TestStateMachine : zx IStateMachine
{
public:
TestStateMachine(zx RunOrder** order, zx StateSet** active) : zx IStateMachine(order, active)
{
}
};
TEST_CLASS(StateMachineTest)
{
public:
TEST_METHOD(IStateMachineTest)
{
auto* order = new zx RunOrder();
auto* active = new zx StateSet();
TestStateMachine test = TestStateMachine(&order, &active);
}
};
I removed all your macro stuff, and #includes with missing header files, provided a replacement for tstring like typedef std::basic_string<TCHAR> tstring; and an implementation for const tstring& IState::name() { return pm_name; } and the code compiles without error.
Assuming that USINGZX is using namespace zx; then this code does not define IStateMachine::IStateMachine in the zx namespace, it's in the global namespace.
USINGZX;
IStateMachine::IStateMachine(): pm_states(StateMap()), pm_runOrder(nullptr), pm_activeStates(nullptr)
{
SetUpDefaultState();
}
If you want to define IStateMachine::IStateMachine in the zx namespace then you've either got to say
zx::IStateMachine::IStateMachine(): pm_states(StateMap()), pm_runOrder(nullptr), pm_activeStates(nullptr)
{
SetUpDefaultState();
}
or
namespace zx {
IStateMachine::IStateMachine(): pm_states(StateMap()), pm_runOrder(nullptr), pm_activeStates(nullptr)
{
SetUpDefaultState();
}
}
So here's my problem. I'm writing web browser plugin in Firebreath. Plugin has to connect to different databases (Firebird, MS SQL, My SQL etc.) depending on client request. So I'm creating class to manage connection to right DB. To connect to Firebird I'm trying to use IBPP. I managed to connect to FB using IBPP in simple test project. But now when I'm doing something much more complex I've got this strange linker error LNK2019.
Exact error message is:
Error 2 error LNK2019: unresolved external symbol "class IBPP::Ptr<class IBPP::IDatabase>
__cdecl IBPP::DatabaseFactory(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
const &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
const &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
const &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
const &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
const &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
const &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &)
" (?DatabaseFactory#IBPP##YA?AV?$Ptr#VIDatabase#IBPP###1#ABV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##000000#Z)
referenced in function "class IBPP::Ptr<class IBPP::IDatabase>
__cdecl IBPP::DatabaseFactory(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
const &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
const &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
const &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &)"
(?DatabaseFactory#IBPP##YA?AV?$Ptr#VIDatabase#IBPP###1#ABV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##000#Z)
C:\ff-extensions\F4U\build\projects\F4UConv\Connections.obj F4UConv
Code for my connections looks like this:
Header
#ifndef Connections_h
#define Connections_h
#include <cstdarg>
#include <string>
#include "ibpp\ibpp.h"
#include "..\Logger\Logger.h"
using namespace std;
namespace Connections{
class Connection {
public:
void set_logger(Logger::Logger *logger);
virtual bool setup_connection(string machine, string db_path, string login, string passwd)=0;
virtual bool connect()=0;
virtual bool disconnect()=0;
virtual bool setup_statement(string sql_statement, const char *fmt, ...)=0;
template <class Statement>
Statement execute_statement();
protected:
string machine;
string db_path;
string login;
string passwd;
Logger::Logger *logger;
};
class FB_Connection : public Connection {
public:
~FB_Connection();
bool setup_connection(string machine, string db_path, string login, string passwd);
bool connect();
bool disconnect();
bool setup_statement(string sql_statement, const char *fmt, ...);
template <class Statement>
Statement execute_statement();
private:
IBPP::Database db;
};
};
#endif Connections_h
Source
#include "Connections.h"
namespace Connections{
void Connection::set_logger(Logger::Logger *logger){
this->logger = logger;
}
FB_Connection::~FB_Connection(){
if(this->db->Connected()){
this->disconnect();
}
db->Drop();
}
bool FB_Connection::setup_connection(string machine, string db_path, string login, string passwd){
this->machine = machine;
this->db_path = db_path;
this->login = login;
this->passwd = passwd;
try{
this->db = IBPP::DatabaseFactory(this->machine, this->db_path, this->login, this->passwd);
this->db->Create(3);
}catch(IBPP::Exception& e){
if(logger != nullptr){
this->logger->log(Logger::LogMsgValue[Logger::E_LOGMSG_000002]);
this->logger->log(Logger::LEVEL_ERROR, e.ErrorMessage());
}
return false;
}
return true;
}
bool FB_Connection::connect(){
return true;
}
bool FB_Connection::disconnect(){
return true;
}
bool FB_Connection::setup_statement(string sql_statement, const char *fmt, ...){
return true;
}
template <class Statement>
Statement FB_Connection::execute_statement(){
return this;
}
}
I'm googling for two days and still don't know what's the problem. I understand what LNK2019 error means but don't know why it occurs in this case.
The line that generate this error is:
this->db = IBPP::DatabaseFactory(this->machine, this->db_path, this->login, this->passwd);
Can anyone show me what's wrong?
Oh, and I'm using Visual Studio 2012 Express.
You are trying to access the method in the source for which you haven't provided the definition in the connection namespace , i.e
This method :
DatabaseFactory(this->machine, this->db_path, this->login, this->passwd);
Provide a definition for it in the connection namespace.
Write using namespace connections; in the source file.