避免未使用的变量在 C++ 中被优化?

问题描述 投票:0回答:1

我正在尝试利用构造未使用变量的副作用,因此我不希望它被优化。

好的,我知道在构造变量时使用副作用可能不是一个好的做法。那么请允许我解释一下目前的情况。

我有一个抽象类和一个具体类。我已经实现了一个工厂,它生成指向具体类的

Abstract*
指针。对于任何希望由抽象类产生的具体类,必须首先注册它们。这是一个最小的(非)工作示例:

// Abstract.hpp
#pragma once

class Abstract {
public:
    virtual void Hello() const = 0;
};
// Abstract.cc
#include "Abstract.hpp"
#include "Factory.hpp"

template<>
Factory<Abstract>* Factory<Abstract>::_the_factory = nullptr;
// Concrete.hpp
#include "Abstract.hpp"
#include "iostream"

class Concrete : public Abstract {
public:
    void Hello() const override {
        std::cerr << "B" << std::endl;
    }
};
// Concrete.cc
#include "Concrete.hpp"
#include "Factory.hpp"

const bool concrete_registered = Factory<Abstract>::GetInstance()->Register("concrete", []() {
    return new Concrete;
});
// Factory.hpp
#pragma once
#include <map>
#include <string>
#include <functional>
#include <iostream>

template <class Product>
class Factory {
public:
    using ProductCreator = std::function<Product*()>;

    static Factory* GetInstance() {
        if (!_the_factory) {
            _the_factory = new Factory;
        }
        return _the_factory;
    }

    bool Register(const std::string& name, const ProductCreator& creator) {
        bool result = _creator_map.insert(std::make_pair(name, creator)).second;
        if (result) {
            std::cerr << name << " registered" << std::endl;
        } else {
            std::cerr << name << " can't be registered" << std::endl;
        }
        return result;
    }

    Product* GetProduct(const std::string& name) {
        if (_creator_map.find(name) == _creator_map.end()) {
            std::cerr << "Unknown product name " << name << " detected";
        }
        return _creator_map[name]();
    }

private:
    static Factory* _the_factory;
    std::map<std::string, ProductCreator> _creator_map;
};

我希望通过将

concrete_registered
设置为常量,我可以强制程序在
main
之前执行注册代码,以便我可以从工厂获得
Concrete
的产品。以下是我如何使用它们:

// main.cc
#include "Abstract.hpp"
#include "Factory.hpp"

int main() {
    auto ptr = Factory<Abstract>::GetInstance()->GetProduct("concrete");
    ptr->Hello();
}

整个项目的结构如下:

├── CMakeLists.txt
├── lib
│   ├── Abstract.cc
│   ├── Abstract.hpp
│   ├── CMakeLists.txt
│   ├── Concrete.cc
│   ├── Concrete.hpp
│   └── Factory.hpp
└── main.cc

我的

CMakeLists.txt
是:

# CMakeLists.txt
cmake_minimum_required(VERSION 3.22)
project(test)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

add_subdirectory(lib)
add_executable(main main.cc)
target_link_libraries(main lib)
# lib/CMakeLists.txt
add_library(lib Abstract.cc Concrete.cc)
target_include_directories(lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

但是,运行程序时出现以下错误:

terminate called after throwing an instance of 'std::bad_function_call'

事实上,我没有看到表明

Concrete
对象成功注册的日志(请注意登录
Factory.hpp

花了一些时间搜索这个问题后,我意识到这可能是变量

concrete_registered
未使用的结果,因此链接器没有将其链接到主程序。这就是为什么我需要使用构造未使用的变量的副作用。

我的问题:是否可以强制 C++ 链接器将

concrete_registered
链接到主程序?我知道一些技巧,例如
-Wl,--whole-archive -lXXX -Wl,--no-whole-archive
但我担心链接整个目标可能太多,我只需要这部分代码“未优化”

c++ linker compiler-optimization auto-registration
1个回答
0
投票

更好地阅读,这是图书馆运作方式的副作用。当你有一个库 mylib.a 时,它有许多目标文件

文件1.o、文件2.o、文件3.o

当引用它们时,它们被链接器拉入二进制文件。您的系统创建了crete.o,没有导出数据,因此链接器不会将其添加到您的二进制文件中。链接器无法看到从 main.cc 到工厂的抽象查找(在 main.cc 中实现),并且认为为了使系统正常工作,需要将crete.o 添加到二进制文件中。

尝试使用 objdump 查看实现在哪里。

您需要将具体类中的符号拉入二进制文件中,否则它将无法工作

© www.soinside.com 2019 - 2024. All rights reserved.