C++ 未定义对`vtable for XXX的引用(其中XXX是结构异常)
下面是代码清单6.1.cpp:C++ 未定义对`vtable for XXX的引用(其中XXX是结构异常),c++,multithreading,c++11,thread-safety,C++,Multithreading,C++11,Thread Safety,下面是代码清单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 thr
#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;
}
我有下一个结果:
/tmp/ccqnqlf.o:在函数empty_stack::empty_stack(empty_stack const&')中:
清单6.1.cpp:(.text.ZN11empty_stackC2ERKS_[_zn1empty_stackC5ERKS_]+0x1d):未定义对
vtable for empty_stack'的引用
/tmp/CCQNQLF.o:(.gcc_除外_表+0x20):对空_堆栈的typeinfo的未定义引用'
/tmp/ccqnqlf.o:在函数中
empty_stack::empty_stack()':
清单6.1.cpp:(.text.ZN11empty_stackC2Ev[_ZN11empty_stackC5Ev]+0x16):未定义对vtable for empty_stack的引用'
/tmp/ccqnqlf.o:In function
threadsafe_stack::pop(Msg&)':
清单6.1.cpp:(.text._ZN16threadsafe_stackI3MsgE3popERS0_[_ZN16threadsafe_stackI3MsgE3popERS0_3;]+0x53):对空_堆栈的typeinfo的未定义引用
/tmp/ccqnqlf.o:在函数中
empty_stack::~empty_stack()
清单6.1.cpp:(.text.ZN11empty_stackD2Ev[ZN11empty_stackD5Ev]+0xb):对“vtable for empty_stack”的未定义引用
collect2:错误:ld返回了1个退出状态您没有定义
空\u堆栈::什么
因为这意味着您没有定义empty_stack
的任何成员,而且因为它是多态的(因为std::exception
有一个虚拟析构函数),这意味着没有为它创建虚拟表,所以您会得到这个看起来很奇怪的错误
如果为empty_stack
定义了一个虚拟析构函数,则不会得到有关虚拟表的任何错误:
struct empty_stack : std::exception
{
~empty_stack() {}
const char* what() const throw();
};
<>但是,您仍然会收到关于<代码> EMPTYStAs::什么是如果您尝试使用它的链接错误, < P>从C++ FAQ:
许多编译器将这个神奇的“虚拟表”放在定义类中第一个非内联虚拟函数的编译单元中。因此,如果Fred中的第一个非内联虚拟函数是wilma(),编译器将把Fred的虚拟表放在它看到Fred::wilma()的同一个编译单元中。不幸的是,如果您不小心忘记定义Fred::wilma(),而不是得到一个未定义的Fred::wilma(),您可能会得到一个“Fred的虚拟表未定义”。悲伤但真实
()
因此,您需要定义
empty_stack::what
在大多数情况下,LNK2001未定义的引用链接器错误是由于缺少定义而发生的
在您的情况下,编译器无法找到public:virtual char const*\uu thiscall empty\u stack::what(void)const“
尝试为空堆栈给出适当的定义::what(void)const希望这对您有用。您需要实现
const char* what() const throw();
在空的_堆栈类中
但仍然要小心使用threadsafe_堆栈。
尤其是这个方法是空的。
此方法可能会锁定线程,但在返回堆栈状态后,会释放锁,因此该值无效。
您需要锁定线程并询问状态,并在不释放锁的情况下使用状态
例如:
线程A即将弹出一个值,但线程B要求一个空状态。B很高兴堆栈不是空的,但同时A将弹出最后一项,堆栈是空的。B现在手中有无效状态。您已声明但尚未实现,
empty\u stack::what
Argh”提示“在评论中,答案毫无用处。瘟疫侵袭了我们所有的房子。可能是
const char* what() const throw();