我最近一直在尝试使用 GCC 11 将代码库转换为 C++20 模块。但是,我遇到了以下情况。首先,这是使用标头完成的方法:
\n啊
\nclass B;\n\nclass A {\n public:\n void f(B& b);\n};\nRun Code Online (Sandbox Code Playgroud)\na.cpp
\n#include "A.h"\n#include "B.h"\n\nvoid A::f(B& b)\n{\n // do stuff with b\n}\nRun Code Online (Sandbox Code Playgroud)\n(Bh的内容在这里并不重要)
\n需要注意的是 B 的前向声明。并不是每个使用 A 的人都应该关心 B,所以我使用前向声明来阻止重新编译的发生。有了标题,这种情况就完美了。
\n问题在于尝试将此代码转换为模块时。主要问题是实体与声明它们的模块相关联,因此在 Ah 中向前声明是不可能的。我尝试在全局模块中进行前向声明,但编译器仍然抱怨 B 的定义与其声明位于不同的模块中。我还尝试使用第三个模块,其中仅包含 B 的前向声明,但这仍然是在两个不同的模块中声明和定义 B。所以,我的主要问题是:如何从模块外部转发声明某些内容? 我也会对最终产生相同效果的方式感到满意:当 B 更改时,A 的用户不需要重新编译。
\n在搜索时,我发现了一些地方谈论类似的情况,但由于某种原因它们都不起作用。他们不起作用的原因:
\n编辑:为了回应评论,以下是我尝试过的一些事情的详细信息:
\n尝试 1:在 A.mpp 中转发声明 …
每一两年我都会决定尝试使用 C++ 模块,但每次我都会遇到问题,通常是与编译器有关。但这一次我的问题似乎出在规范本身,而且我似乎找不到解决方法。
考虑一个带有 header 的第三方库foo.hpp。中foo.hpp,它包括<string>. 假设由于某种原因(可能是因为奇怪的宏使用),foo.hpp无法将其编译为标头单元,因此必须将其编译为#included。<string>我的问题来自于尝试同时使用这个库。
想法#1:
module;
#include <foo.hpp>
export module A;
import <string>;
...
Run Code Online (Sandbox Code Playgroud)
据我了解,这里的问题是<string>包含在 中,但是在导入 时不会应用foo.hpp包含的标头防护,从而导致 odr 违规。<string><string>
想法#2:
export module A;
import <string>;
#include <foo.hpp>
...
Run Code Online (Sandbox Code Playgroud)
因为标头单元确实定义了宏,所以这修复了 odr 违规,当foo.hpp包含时标头防护会启动<string>。然而,这最终将 的所有内容定义foo.hpp为 module 中的实体A,这是不正确的并会导致各种问题。
想法#3:
module;
#include <foo.hpp>
export module A;
...
Run Code Online (Sandbox Code Playgroud)
这背后的想法是,如果foo.hpp已经包含<string>,为什么还要尝试再次获取它呢?问题是这在更复杂的情况下不起作用。是说我不是导入<string>,而是导入了另一个导出导入的模块<string>?或者也许是更复杂的事情?最终这个解决方案无法扩展。 …
我正在尝试制作一个多线程程序但是线程局部向量有一个奇怪的问题.这是(精简到只有错误)代码:
#include <vector>
#include <iostream>
thread_local std::vector<int> vec;
int main(){
vec.push_back(3);
std::cout << vec[0];
// Make you push enter to show the error is at the end
std::cin.ignore();
}
Run Code Online (Sandbox Code Playgroud)
该程序编译良好,运行大多数罚款,但在我按回车后,我得到一个"程序已停止工作"的消息.我在gdb中运行它并得到此错误:
Program received signal SIGSEGV, Segmentation fault.
0x004030b0 in std::vector<int, std::allocator<int> >::~vector() ()
Run Code Online (Sandbox Code Playgroud)
不知何故,向量的析构函数中存在错误.使用断点查看它会显示该错误在程序退出时发生.
使向量不是本地的线程使程序工作,但当然我需要它是线程本地的.如果我根本不与矢量交互,程序运行正常.
我想我将不得不使用一些替代方案,但有人知道一种方法来使这项工作?谢谢!
编辑:我很愚蠢,忘了更多关于我的系统的信息.我正在使用Windows Vista 64位.运行g ++ -v给了我:
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=C:/MinGW/bin/../libexec/gcc/i686-w64-mingw32/5.2.0/lto-wrapper.exe
Target: i686-w64-mingw32
Configured with [edited out because it's too big and probably not relevant]
Thread model: posix
gcc version 5.2.0 (i686-posix-dwarf-rev0, Built by MinGW-W64 project) …Run Code Online (Sandbox Code Playgroud) 这个问题令人困惑,所以这是我正在尝试做的精简版本:
#include <memory>
#include <iostream>
class A {
};
class B : public A {
public:
std::unique_ptr<A> a;
};
class C : public A {
public:
int var;
};
int main()
{
C* c = new C;
B* b = new B;
c->var = 3;
b->a = std::unique_ptr<A>(c);
std::unique_ptr<A> aa(b);
aa = std::move(static_cast<B*>(aa.get())->a);
std::cout << static_cast<C*>(aa.get())->var;
}
Run Code Online (Sandbox Code Playgroud)
这就是我所做的:
- 创建一个类,它自己拥有一个 unique_ptr(我的具体情况是多态的,所以这就是我在这里所做的)
- 为该类创建一个 unique_ptr
- 将外部 unique_ptr 分配给内部的值
现在,最后一步将销毁 unique_ptr 指向的对象。我分配给它的值在那个即将被删除的对象中。但是,通过移动它,它可能不再在那里了。
虽然这段代码编译并运行良好(在 valgrind 中也是如此),但我想知道:这安全吗?是否发生了一些我没有意识到的令人讨厌的事情?这样做有什么注意事项吗?
编辑:我忘了放入虚拟析构函数。假设所有三个类都有。它在我的实际代码中。