C++类名冲突
C++ class name collision
对于以下C++代码,我遇到了意外的行为。该行为已通过最近的GCC,Clang和MSVC++进行了验证。要触发它,需要在多个文件中拆分代码。
Def.H
#pragma once
template<typename T>
struct Base
{
void call() {hook(data);}
virtual void hook(T& arg)=0;
T data;
};
福.H
#pragma once
void foo();
foo.cc
#include "foo.h"
#include <iostream>
#include "def.h"
struct X : Base<int>
{
virtual void hook(int& arg) {std::cout << "foo " << arg << std::endl;}
};
void foo()
{
X x;
x.data=1;
x.call();
}
酒吧.H
#pragma once
void bar();
bar.cc
#include "bar.h"
#include <iostream>
#include "def.h"
struct X : Base<double>
{
virtual void hook(double& arg) {std::cout << "bar " << arg << std::endl;}
};
void bar()
{
X x;
x.data=1;
x.call();
}
main.cc
#include "foo.h"
#include "bar.h"
int main()
{
foo();
bar();
return 0;
}
预期产出:
foo 1
bar 1
实际输出:
bar 4.94066e-324
bar 1
我期望发生的事情:
在 foo.cc 内部,创建了一个在 foo.cc 中定义的 X 实例,并通过调用 call((,调用了 foo.cc 中 hook(( 的实现。酒吧也一样。
实际发生的情况:
foo.cc 中定义的 X 实例是在 foo(( 中创建的。但是当调用调用时,它不是调度到 foo.cc 中定义的 hook((,而是调度到 bar.cc 中定义的 hook((。这会导致损坏,因为钩子的参数仍然是一个整数,而不是一个双精度。
这个问题可以通过将 X 的定义放在 foo.cc 中,而不是在 bar.cc 中定义 X 来解决这个问题
所以最后的问题是:没有编译器对此的警告。gcc、clang 或 MSVC++ 都没有对此发出警告。根据C++标准的定义,该行为是否有效?
这种情况似乎有点建构,但它发生在现实世界的场景中。我正在使用快速检查编写测试,其中对要测试的单元的可能操作定义为类。 大多数容器类都有类似的操作,因此在为队列和向量编写测试时,名称为"清除"、"推送"或"Pop"的类可能会出现多次。由于这些仅在本地需要,因此我将它们直接放在执行测试的源中。
该程序格式不正确,因为它违反了单定义规则,因为它对类X
有两个不同的定义。因此,它不是一个有效的C++程序。请注意,该标准特别允许编译器不诊断此冲突。因此,编译器是符合要求的,但程序C++无效,因此在执行时具有未定义的行为(因此任何事情都可能发生(。
您有两个名称相同但不同的类X
在不同的编译单元中,导致程序格式不正确,因为现在有两个具有相同名称的符号。由于问题只能在链接期间检测到,因此编译器无法(也不需要(报告此问题。
避免此类事情的唯一方法是将任何不打算导出的代码(特别是尚未在头文件中声明的所有代码(放入匿名或未命名的命名空间中:
#include "foo.h"
#include <iostream>
#include "def.h"
namespace {
struct X : Base<int>
{
virtual void hook(int& arg) {std::cout << "foo " << arg << std::endl;}
};
}
void foo()
{
X x;
x.data=1;
x.call();
}
等同于bar.cc
.事实上,这是未命名命名空间的主要(唯一?(目的。
只需重命名您的类(例如fooX
和barX
( 在实践中可能适合您,但不是稳定的解决方案,因为无法保证这些符号名称不会被在链接或运行时(现在或将来的某个时间点(加载的某些晦涩的第三方库使用。
- 写入位置0x0000000C时发生访问冲突
- GL_SHADERSTORAGE_BUFFER位置是否与其他着色器位置冲突
- 使用cmake从源代码构建MySQL连接器/C++失败(与以前的声明冲突)
- 引发异常:读取访问冲突**dynamicArray**为0x1118235.发生
- C++LinkedList问题.数据类型之间存在冲突?没有匹配的构造函数
- 链表中写入访问冲突的未知原因
- C++中的openCV Mat访问冲突
- 如何使 std::sort 在 std::swap 和我的命名空间的模板化交换之间没有名称冲突?
- C++尝试深度复制唯一指针时出现内存访问冲突
- 错误:使用通用引用的声明冲突
- 如何解决GTest和LibTorch联动冲突
- 两个运营商的一些奇怪的冲突<<
- 如何在多个线程中创建 QSql数据库连接时防止名称冲突
- C++ 中动态二维数组的访问冲突
- 从嵌套循环中的 std::list 中删除将返回访问冲突
- C++17 十六进制浮点文字单精度后缀冲突?
- 结构字段名称与 GDB 中的 STL 数组冲突
- 写入访问冲突异常
- C++ |匿名命名空间与命名空间 std 冲突
- 这个SSDO演示的GLSL版本要求是自我冲突的吗