首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如果另一个翻译单元中存在依赖于构造的副作用的代码,LTO是否允许删除未使用的全局对象?

如果另一个翻译单元中存在依赖于构造的副作用的代码,LTO是否允许删除未使用的全局对象?
EN

Stack Overflow用户
提问于 2019-06-17 09:28:12
回答 3查看 720关注 0票数 3

首先,为了避免XY问题:这个问题来自https://github.com/cnjinhao/nana/issues/445#issuecomment-502080177。库代码可能不应该这样做(依赖于未使用的全局对象的构造),但问题更多的是它是否是有效的LTO行为,而不是代码质量问题。

显示相同问题的最小代码(未经测试,只是为了使示例更小):

代码语言:javascript
复制
// main.cpp
#include <lib/font.hpp>

int main()
{
    lib::font f;
}
代码语言:javascript
复制
// lib/font.hpp
namespace lib
{
struct font
{
    font();

    int font_id;
};
}
代码语言:javascript
复制
// lib/font.cpp
#include <lib/font.hpp>
#include <lib/font_abstraction.hpp>

namespace lib
{
font::font()
{
    font_id = get_default_font_id();
}
}
代码语言:javascript
复制
// lib/font_abstraction.hpp
namespace lib
{
int get_default_font_id();

void initialize_font();
}
代码语言:javascript
复制
// lib/font_abstraction.cpp
#include <lib/font_abstraction.hpp>

namespace lib
{
static int* default_font_id;

int get_default_font_id()
{
    return *default_font_id;
}

void initialize_font()
{
    default_font_id = new int(1);
}
}
代码语言:javascript
复制
// lib/platform_abstraction.hpp
namespace lib
{
struct platform_abstraction
{
    platform_abstraction();
};
}
代码语言:javascript
复制
// lib/platform_abstraction.cpp
#include <lib/platform_abstraction.hpp>
#include <lib/font_abstraction.hpp>

namespace lib
{
platform_abstraction::platform_abstraction()
{
    initialize_font();
}

static platform_abstraction object;
}

font对象在main.cpp中的构造依赖于指针的初始化。唯一初始化指针的是全局对象object,但它没有被起诉-在链接问题的情况下,该对象被LTO删除。允许这样的优化吗?(请参阅C++草案6.6.5.1.2)

一些注意事项:

  • 该库是作为静态库构建的,并使用-flto -fno-fat-lto-objects和动态C++标准库与主文件链接。
  • 这个示例可以在不编译lib/platform_abstraction.cpp的情况下构建--在这种情况下,指针将不会被确定地初始化。
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-06-17 15:02:16

VTT的回答给出了GCC的答案,但问题是有标记的语言--律师。

ISO C++的原因是在第一次调用同一个翻译单元中定义的函数之前,必须初始化在翻译中定义的对象。这意味着必须在调用platform_abstraction::object之前初始化platform_abstraction::platform_abstraction()。正如链接器正确指出的那样,没有其他的platform_abstraction对象,所以platform_abstraction::platform_abstraction永远不会被调用,因此object的初始化可以无限期地推迟。符合的程序无法检测到这一点。

票数 5
EN

Stack Overflow用户

发布于 2019-06-17 09:39:59

由于您从未在主可执行文件中引用静态库中的object,除非您将该静态库与-Wl,--whole-archive链接起来,否则它将不存在。无论如何,依赖于一些全局对象的构造来执行初始化并不是一个好主意。因此,您应该在使用该库中的其他函数之前显式地调用initialize_font

关于带有问号的语言的补充解释-律师:

static platform_abstraction object;在任何情况下都不能根据

6.6.4.1静态存储持续时间basic.stc.static 2如果具有静态存储持续时间的变量具有初始化或具有副作用的析构函数,则即使该变量似乎未使用,也不应消除该变量,除非类对象或其副本/移动可以按照15.8中的规定予以消除。

这是怎么回事?在链接静态库(对象文件的存档)时,默认情况下,链接器只会选择填充未定义符号所需的对象文件,而且由于platform_abstraction.cpp中的内容不在任何地方使用,其他链接器将完全忽略此转换单元。--whole-archive选项通过强制链接器链接静态库中的所有对象文件来更改此默认行为。

票数 5
EN

Stack Overflow用户

发布于 2019-07-27 20:44:34

没有全局静态变量。

初始化顺序未定义(一般情况下)。

将静态对象作为静态对象放入函数中,这样您就可以保证在使用之前创建它们。

代码语言:javascript
复制
namespace lib
{
static int* default_font_id;

int get_default_font_id()
{
    return *default_font_id;
}

void initialize_font()
{
    default_font_id = new int(1);
}
}

//也改变这一点:

代码语言:javascript
复制
namespace lib
{

int get_default_font_id()
{
     // This new is guaranteed to only ever be called once.
     static std::unique_ptr<int> default_font_id = new int(1);

     return *default_font_id;
}

void initialize_font()
{
    // Don't need this ever.
}
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56628469

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档