我正在尝试使用Clang-3.5编译以下简单的C++代码:
test.h:
class A
{
public:
A();
virtual ~A() = 0;
};
Run Code Online (Sandbox Code Playgroud)
test.cc:
#include "test.h"
A::A() {;}
A::~A() {;}
Run Code Online (Sandbox Code Playgroud)
我用来编译它的命令(Linux,uname -r:3.16.0-4-amd64):
$clang-3.5 -Weverything -std=c++11 -c test.cc
Run Code Online (Sandbox Code Playgroud)
而我得到的错误:
./test.h:1:7: warning: 'A' has no out-of-line virtual method definitions; its vtable will be emitted in every translation unit [-Wweak-vtables]
Run Code Online (Sandbox Code Playgroud)
任何暗示为什么会发出警告?虚拟析构函数根本没有内联.恰恰相反,test.cc中提供了一个外联定义.我在这里错过了什么?
编辑
我不认为这个问题是重复的:
clang的-Wweak-vtables是什么意思?
正如FilipRoséen所说.在我的问题中,我特别提到纯抽象类(在建议的副本中没有提到).我知道如何-Wweak-vtables使用非抽象类,我很好.在我的例子中,我在实现文件中定义了析构函数(它是纯抽象的).这应该可以防止Clang发出任何错误,即使是-Wweak-vtables.
关于此主题的先前问题:
这是我最近提出的问题的后续跟进: clang:没有外线虚拟方法定义(纯抽象C++类) ,并且被标记为此问题的副本:clang的-Wweak-含义是什么?虚函数表?.我不认为那回答了我的问题,所以在这里我专注于困扰我的事情,但尚未得到回答.
我的情景:
我正在尝试使用Clang-3.5编译以下简单的C++代码:
test.h:
class A
{
public:
A();
virtual ~A() = 0;
};
Run Code Online (Sandbox Code Playgroud)
test.cc
#include "test.h"
A::A() {;}
A::~A() {;}
Run Code Online (Sandbox Code Playgroud)
我用来编译它的命令(Linux,uname -r:3.16.0-4-amd64):
$clang-3.5 -Wweak-vtables -std=c++11 -c test.cc
Run Code Online (Sandbox Code Playgroud)
而我得到的错误:
./test.h:1:7: warning: 'A' has no out-of-line virtual method definitions; its vtable will be emitted in every translation unit [-Wweak-vtables]
Run Code Online (Sandbox Code Playgroud)
当A类不是纯抽象时,上面的代码构建得很好.以下代码不会发出警告,唯一的变化是A类不再是抽象的:
test2.h:
class A
{
public:
A();
virtual ~A();
};
Run Code Online (Sandbox Code Playgroud)
test2.cc
#include "test2.h"
A::A() {;}
A::~A() {;}
Run Code Online (Sandbox Code Playgroud)
我的问题
上面的代码在Clang中触发警告的纯抽象类有什么特别之处?
我一直在尝试了解LLVM的GetElementPtr(GEP)指令,并遇到了此文档:
http://llvm.org/docs/GetElementPtr.html
这非常有帮助,但是有些事情让我感到困惑。特别是在“ GEP取消引用了什么?”部分中。(http://llvm.org/docs/GetElementPtr.html#id6)讨论了以下代码:
%MyVar = uninitialized global { [40 x i32 ]* }
...
%idx = getelementptr { [40 x i32]* }, { [40 x i32]* }* %MyVar, i64 0, i32 0, i64 0, i64 17
Run Code Online (Sandbox Code Playgroud)
%MyVar是一个全局变量,它是一个指向包含40个int数组的指针的结构的指针。这很清楚。我知道后面%MyVar的参数是它的索引,但是我不明白为什么其中一些声明为,i64而另一些声明为i32。
我的理解是该代码是为64位计算机编写的,并且指针被假定为64位宽。指向的数组的内容为%MyVar32位宽。那么为什么最后一个索引i64 17而不是i32 17?
我还应该指出,此示例说明了GEP的非法用法(必须取消引用结构中的指针才能索引到40个int的数组),并且我试图很好地理解为什么是这种情况。
我试图理解使用WidgetURef::setName(URef作为一个通用参考,由Scott Meyers创造的术语)与WidgedRRef::setName(RRef作为R值参考)的性能影响:
#include <string>
class WidgetURef {
public:
template<typename T>
void setName(T&& newName)
{
name = std::move(newName);
}
private:
std::string name;
};
class WidgetRRef {
public:
void setName(std::string&& newName)
{
name = std::move(newName);
}
private:
std::string name;
};
int main() {
WidgetURef w_uref;
w_uref.setName("Adela Novak");
WidgetRRef w_rref;
w_rref.setName("Adela Novak");
}
Run Code Online (Sandbox Code Playgroud)
我很欣赏通用引用应该使用std::forward,但这只是一个(不完美的)示例,以突出有趣的位.
问题
在这个特定的例子中,使用一个实现与另一个实现的性能影响是什么?虽然WidgetURef需要类型扣除,但它在其他方面是相同的WidgetRRef,不是吗?至少在这种特殊情况下,在两种情况下,参数都是r-value引用,因此不会创建临时值.这个推理是否正确?
背景
这个例子来自Scott Meyers的"Effective Modern C++"(p.170)的第25项.根据这本书(假设我的理解是正确的!),采用通用引用的版本T&&不需要临时对象而另一个需要临时对象std::string&&.我真的不明白为什么.