我有下一个代码列表-6.1.cpp:
#include <stack>
#include <mutex>
#include <memory>
#include <future>
#include <iostream>
#include <exception>
using namespace std;
struct empty_stack: std::exception
{
const char* what() const throw();
};
template<typename T>
class threadsafe_stack
{
private:
std::stack<T> data;
mutable std::mutex m;
public:
threadsafe_stack(){}
threadsafe_stack(const threadsafe_stack& other)
{
std::lock_guard<std::mutex> lock(other.m);
data=other.data;
}
threadsafe_stack& operator=(const threadsafe_stack&) = delete;
void push(T new_value)
{
std::lock_guard<std::mutex> lock(m);
data.push(std::move(new_value));
}
std::shared_ptr<T> pop()
{
std::lock_guard<std::mutex> lock(m);
if(data.empty()) throw empty_stack();
std::shared_ptr<T> const res(
std::make_shared<T>(std::move(data.top())));
data.pop();
return res;
}
void pop(T& value)
{
std::lock_guard<std::mutex> lock(m);
if(data.empty()) throw empty_stack();
value=std::move(data.top());
data.pop();
}
bool empty() const
{
std::lock_guard<std::mutex> lock(m);
return data.empty();
}
};
struct Msg {
size_t a;size_t b;size_t c;size_t d;
};
bool isCorrupted(const Msg& m) {
return !(m.a == m.b && m.b == m.c && m.c == m.d);
}
int main()
{
threadsafe_stack<Msg> stack;
auto prod = std::async(std::launch::async, [&]() {
for (size_t i = 0; i < 1000000; ++i){
Msg m = { i, i, i, i };
stack.push(m);
//std::this_thread::sleep_for(std::chrono::microseconds(1));
if (i % 1000 == 0) {
std::cout << "stack.push called " << i << " times " << std::endl;
}
}
});
auto cons = std::async(std::launch::async, [&]() {
for (size_t i = 0; i < 1000000; ++i){
try {
Msg m;
stack.pop(m);
if (isCorrupted(m)) {
std::cout << i <<" ERROR: MESSAGE WAS CORRUPED:" << m.a << "-" << m.b << "-" << m.c << "-" << m.d << std::endl;
}
if (i % 1000 == 0) {
std::cout << "stack.pop called " << i << " times " << std::endl;
}
}
catch (empty_stack e) {
std::cout << i << " Stack was empty!" << std::endl;
}
}
});
prod.wait();
cons.wait();
return 0;
}
用以下代码编译后:
g++ -o exe.out listing-6.1.cpp -pthread -lboost_system -lboost_thread -std=c++0x
我有下一个结果:
/tmp/ccqQnqlf.o:函数empty_stack::empty_stack(empty_stack const&)':
listing-6.1.cpp:(.text._ZN11empty_stackC2ERKS_[_ZN11empty_stackC5ERKS_]+0x1d): undefined reference to
vtable for empty_stack'
/tmp/ccqQnqlf.o:(.gcc_except_table+0x20):对typeinfo for empty_stack'
/tmp/ccqQnqlf.o: In function
empty_stack :: empty_stack()'的未定义引用:
listing-6.1.cpp :(。text._ZN11empty_stackC2Ev [_ZN11empty_stackC5Ev] + 0x16):对vtable for empty_stack'
/tmp/ccqQnqlf.o: In function
threadsafe_stack :: pop(Msg&amp;)'的未定义引用:
listing-6.1.cpp :(。text._ZN16threadsafe_stackI3MsgE3popERS0 _ [_ ZN16threadsafe_stackI3MsgE3popERS0 _] + 0x53):对typeinfo for empty_stack'
/tmp/ccqQnqlf.o: In function
empty_stack ::〜empty_stack()'的未定义引用:
listing-6.1.cpp :(。text._ZN11empty_stackD2Ev [_ZN11empty_stackD5Ev] + 0xb):未定义引用`vtable for empty_stack'
collect2:错误:ld返回1退出状态
答案 0 :(得分:1)
您没有定义empty_stack::what
。
因为这意味着您没有定义 empty_stack
的任何成员,并且因为它是多态的(因为std::exception
有一个虚拟析构函数),这意味着没有虚拟表是为它创建的,所以你会得到这个特殊的错误。
如果您为empty_stack
定义了虚拟析构函数,那么您将不会收到有关虚拟表的任何错误:
struct empty_stack : std::exception
{
~empty_stack() {}
const char* what() const throw();
};
但如果您尝试使用empty_stack::what
,则仍会收到有关{{1}}的链接器错误。
答案 1 :(得分:1)
在大多数情况下,LNK2001由于定义缺失而发生未定义的引用链接器错误。!
在您的情况下,编译器无法找到public: virtual char const * __thiscall empty_stack::what(void)const "
尝试给empty_stack::what(void)const
提供适当的定义。希望这对您有用。
答案 2 :(得分:0)
来自C ++ FAQ:
许多编译器将这个神奇的“虚拟表”放在编译单元中,该单元定义了类中的第一个非内联虚函数。因此,如果Fred中的第一个非内联虚函数是wilma(),编译器会将Fred的虚拟表放在它看到Fred :: wilma()的同一个编译单元中。不幸的是,如果您不小心忘记定义Fred :: wilma(),而不是未定义Fred :: wilma(),您可能会得到“Fred的虚拟表未定义”。伤心但真实。
(http://www.parashift.com/c++-faq/link-errs-missing-vtable.html)
因此,您需要定义empty_stack::what
答案 3 :(得分:0)
您需要实施
const char* what() const throw();
<_>在empty_stack类中。
但是,请小心使用你的threadsafe_stack。 特别是方法空了。 此方法可能是锁定线程,但在返回堆栈状态后,锁定被释放,因此该值无用。 您需要锁定线程并询问状态并使用状态而不释放锁定。
实施例: 线程A即将弹出一个值,但是线程B要求空状态。 B很高兴堆栈不为空,但同时A将弹出最后一项并且堆栈为空。 B现在手中的状态无效。