c++ - 这些链接错误是什么意思? (C++)(MSVC++)

标签 c++ templates linker

编辑:当我将link_def.cpp与link_dec.h合并时,我只会得到第一个错误,而不是第二个错误。

当我尝试编译一些代码时,出现了这些链接器错误:
码:

#include"list_dec.h"
#include"catch.h"

int main()
{
    list<int, 100> L1;
    try
    {
        L1.return_current();
    }
    catch(err)
    {
        return -1;
    }
    return 0;
}

错误:
Linking...
main.obj : error LNK2019: unresolved external symbol "public: __thiscall list<int,100>::~list<int,100>(void)" (??1?$list@H$0GE@@@QAE@XZ) referenced in function __catch$_main$0
main.obj : error LNK2019: unresolved external symbol "public: int __thiscall list<int,100>::return_current(void)" (?return_current@?$list@H$0GE@@@QAEHXZ) referenced in function _main
main.obj : error LNK2019: unresolved external symbol "public: __thiscall list<int,100>::list<int,100>(void)" (??0?$list@H$0GE@@@QAE@XZ) referenced in function _main

如果有人需要list_dec.h,catch.h和list_def.cpp(列表类的定义)的代码,则只需评论一下,尽管它们很无关紧要,但我不想包括它们,因为它们很大。

由于有人想查看list_dec.h(我暂时将其与list_def.cpp合并了)
list_dec.h:
template<class T, size_t limit>
class list
{
public:
    //constructors
    list();
    list(const list<T, limit>& lst);
    ~list();

    //assignment operator
    void operator=(const list<T, limit>& lst);

    //append new items
    void append(const T& item);

    //clear the list
    void clear();

    //return current item
    T return_current();

    //test if item is last item
    bool last();

    //make current item head of the list
    void make_head();

    //move to the next item
    bool next();

    //interrogation
    size_t return_count();
    size_t return_limit();

protected:
    size_t count; //# of items in list
    size_t current; //current item
    T data[limit]; //array of elements of list

    //internal functions
    void copy(const list<T, limit>& lst);
};



//copier function
template<class T, size_t limit>
void list<T, limit>::copy(const list<T, limit>& lst)
{
    count = lst.count;
    current = lst.current;

    for(size_t n = 0; n < count; n++)
    {
        data[n] = lst.data[n];
    }
    return;
}

//constructor
template<class T, size_t limit>
inline list<T, limit>::list()
{
    count = 0;
    current = 0;
}

//copy constructor
template<class T, size_t limit>
inline list<T, limit>::list(const list<T, limit>& lst)
{
    copy(lst);
}

//assignment operator
template<class T, size_t limit>
inline void list<T, limit>::operator=(const list<T, limit>& lst)
{
    clear();
    copy(lst);
    return;
}

//destructor
template<class T, size_t limit>
inline list<T, limit>::~list()
{
    clear();
}

//append function
template<class T, size_t limit>
void list<T, limit>::append(const T& item)
{
    if(count == limit)
    {
        throw CX_OVERFLOW;
    }
    data[count] = item;
    count++;
    return;
}

//return current item
template<class T, size_t limit>
T list<T, limit>::return_current()
{
    if(count == 0)
    {
        throw CX_NULL;
    }
    if(current == count)
    {
        throw CX_ATEND;
    }
    return data[current];
}

//test if <current> pointer is at tail
template<class T, size_t limit>
inline bool list<T, limit>::last()
{
    if(current == count)
    {
        return true;
    }
    else
    {
        return false;
    }
}

//set current pointer to head
template<class T, size_t limit>
inline void list<T, limit>::make_head()
{
    current = 0;
    return;
}

//set current pointer to next pointer in list
template<class T, size_t limit>
bool list<T, limit>::next()
{
    if(count == 0)
    {
        throw CX_NULL;
    }
    if(current == count)
    {
        throw CX_ATEND;
    }

    current++;

    if(current == count)
    {
        return false;
    }

    return true;
}

//interrogation functions
template<class T, size_t limit>
inline size_t list<T, limit>::return_count()
{
    return count;
}
template<class T, size_t limit>
inline size_t list<T, limit>::return_limit()
{
    return limit;
}

最佳答案

可以很轻松地读取链接器错误。试一试吧:

main.obj : error LNK2019: unresolved external symbol "public: __thiscall list<int,100>::~list<int,100>(void)" (??1?$list@H$0GE@@@QAE@XZ) referenced in function __catch$_main$0
  • 错误发生在main.obj中,该文件是从main.cpp生成的目标文件。
  • 问题是“未解析的外部符号”。即,您引用了预期在另一个编译单元中定义的符号,但是链接器找不到该定义。
  • 所涉及的符号是公共(public)成员函数(__thiscall是成员函数的调用约定)。
  • 现在我们来看看真正有用的信息:list<int,100>::~list<int,100>(void)"告诉我们问题出在类模板列表的析构函数上,该模板专门用于<int, 100>。这部分的格式很好,非常简单。对于第二个错误,我们还看到了返回类型:int __thiscall list<int,100>::return_current(void)。也就是说,一个返回int,使用__thiscall调用约定,属于列表的函数称为return_current,并且不带任何参数。
  • ??1?$list@H$0GE@@@QAE@XZ几乎可以忽略。这是符号的名称,由编译器修饰,因此这是链接器在.obj文件中寻找的名称。但是由于链接程序已经告诉我们该符号的可读C++名称,因此我们实际上不需要此名称。 (除非您决定自己亲自挖掘.obj文件)。
  • 最后,它告诉我们在函数main中引用了该符号。 (读取链接器错误时,通常的规则是忽略您不了解的位。我也不完全确定此处的“catch”部分是什么意思,但这与您在main内部执行的异常处理有关。

  • 所以你有它。第一个错误指出找不到列表的析构函数的定义。如果该函数未在类定义中声明为内联,则应在另一个.cpp文件中进行定义。我假设这是您的list_def.cpp,并且该文件也将被编译并传递给链接器。

    但是,这导致我们在模板上遇到了一个小问题。它们是编译时构造,在编译器为其发出代码之前必须实例化模板。在编译器的输出中,类模板list或特化list<int, 84>均不存在任何代码,因为未使用该特化。编译器仅生成实际需要的特化。

    并且,当编译器处理list_def.cpp时,似乎不需要专门化。它无法查看其他.cpp文件,例如您的main.cpp。它只会看到当前正在编译的.cpp文件,以及所有#include的文件。由于看不到list<int, 100>,因此不会为该特化生成任何代码,因此,当将目标文件传递给链接器时,它无法找到list<int, 100>符号的定义并发出错误。

    通常的解决方案是在 header 中内联定义类模板的所有成员。这样,该定义对于包括头文件在内的任何编译单元都是可见的,因此编译器可以创建所需的模板特化名称。

    具体来说,以下将产生链接器错误:
    // .h
    template <int n>
    class Foo {
      int Bar();
    };
    
    // .cpp
    template <int n>
    int Foo::Bar() {
      return n; // Error: This is not visible from other .cpp files
    }
    

    因此,只需将.cpp内容移动到标题中:
    // .h
    template <int n>
    class Foo {
      int Bar();
    };
    
    template <int n>
    int Foo::Bar() {
      return n; // Error: This is will cause the function to be defined in every .cpp file that includes it, so you'll get a *different* linker error instead (multiple definitions)
    }
    

    但这有效,并且是通常的解决方案
    // .h
    template <int n>
    class Foo {
      int Bar() { return n; } // just define it here, inside the class definition, and it is implicitly inline, so it's ok that multiple .cpp files see it
    };
    

    或者:
    // .h
    template <int n>
    class Foo {
      int Bar();
    };
    
    // still in .h
    template <int n>
    inline int Foo::Bar() { // explicitly marking it inline works too. Now the compiler knows that it might be defined in multiple .cpp files, and these definitions should be merged back together
      return n;
    }
    

    一个更不寻常但偶尔有用的解决方案是在定义它的编译单元中显式实例化该模板。因此,在list_def.cpp中,在模板定义之后添加以下行:
    template class list<int, 100>;
    

    这告诉编译器专门为该特化生成代码,即使本编译单元中未使用它也是如此。显然,这种方法仅在您事先知道需要哪些专业的情况下才有用。

    编辑:

    似乎您从未定义过从析构函数调用的clear()函数。这就是在 header 中包含所有内容之后最终链接器错误的原因。

    关于c++ - 这些链接错误是什么意思? (C++)(MSVC++),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/860093/

    相关文章:

    c++ - 如何重写它以使其符合 C++ 标准

    c - C中的Debug/和Release/目录下的lib有什么区别?

    java - 在 ubuntu 上使用 JNI 时出错 : java. lang.UnsatisfiedLinkError : no . .. in java.library.path

    c++ - 如何使用 7z SDK 提取 rar/zip 文件 (C++)?

    c++ - C++ 中的基本继承问题

    c++ - 将 emplace_back 添加到模板类

    visual-studio - 过程入口点无法位于动态链接库 Qt5Cored.dll 中

    c++ - C++ 的平均、最大和最小赋值

    c++ - 是否有像 eclipse cdt 这样的轻型 linux c++ IDE+Visual 调试器?

    C++ 模板元编程静态类型检查