Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/124.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
运行C++;函数范围外的代码 < C++ >强> >(强)>强> >可以> >代码>声明变量超出范围,并且 > < < /强> >运行任何代码/语句,除了初始化全局/静态变量。< /P>_C++_Static_Initialization_Initializer - Fatal编程技术网

运行C++;函数范围外的代码 < C++ >强> >(强)>强> >可以> >代码>声明变量超出范围,并且 > < < /强> >运行任何代码/语句,除了初始化全局/静态变量。< /P>

运行C++;函数范围外的代码 < C++ >强> >(强)>强> >可以> >代码>声明变量超出范围,并且 > < < /强> >运行任何代码/语句,除了初始化全局/静态变量。< /P>,c++,static,initialization,initializer,C++,Static,Initialization,Initializer,创意 为了(例如)进行一些std::map操作,使用下面的复杂代码是一个好主意吗 在这里,我使用void*fakeVar并通过Fake::initializer()对其进行初始化,然后在其中执行任何操作 std::map<std::string, int> myMap; class Fake { public: static void* initializer() { myMap["test"]=222; // Do whatever

创意

为了(例如)进行一些
std::map
操作,使用下面的复杂代码是一个好主意吗

在这里,我使用
void*fakeVar
并通过
Fake::initializer()
对其进行初始化,然后在其中执行任何操作

std::map<std::string, int> myMap;

class Fake
{
public:
    static void* initializer()
    {
        myMap["test"]=222;
        // Do whatever with your global Variables

        return NULL;
    }
};

// myMap["Error"] = 111;                  => Error
// Fake::initializer();                   => Error
void *fakeVar = Fake::initializer();    //=> OK

void main()
{
    std::cout<<"Map size: " << myMap.size() << std::endl; // Show myMap has initialized correctly :)
}
std::map myMap;
类假
{
公众:
静态void*初始值设定项()
{
myMap[“测试”]=222;
//对全局变量执行任何操作
返回NULL;
}
};
//myMap[“错误”]=111;=>错误
//Fake::initializer();=>错误
void*fakeVar=false::initializer();//=>好啊
void main()
{

STD:C++中的CUT< P>,你不能在任何函数外都有语句。但是,你有全局对象声明,并且构造函数(初始化器)调用这些全局对象在主启动之前是自动的。在你的例子中,FAKEVAR是一个全局指针,它通过类静态范围的函数初始化,这绝对是好的。 即使是全局对象也会提供全局对象构造函数执行所需的初始化。 比如说,

class Fake
{
public:
    Fake()     {
        myMap["test"]=222;
        // Do whatever with your global Variables
    }
};
Fake fake; 

解决这个问题的一种方法是让一个类有一个构造函数来做事情,然后声明该类的一个伪变量

struct Initializer
{
    Initializer()
    {
        // Do pre-main initialization here
    }
};

Initializer initializer;
当然,您可以让多个此类类执行杂项初始化。每个翻译单元中的顺序指定为自上而下,但没有指定翻译单元之间的顺序。

§8.5.2规定

除了使用constexpr说明符声明的对象之外 参见7.1.5,变量定义中的初始值设定项可以由 包含文本和先前声明的任意表达式的 变量和函数,与变量的存储持续时间无关

因此,你所做的是完全被C++标准所允许的,也就是说,如果你需要执行“初始化操作”,最好使用类构造函数(例如包装器)。 这是个好主意吗


不太可能。如果有人在他们“棘手的初始化”中决定了这一点怎么办他们想使用您的映射,但在某些系统或其他系统上,或者在特定的重新链接后由于不明显的原因,您的映射在尝试使用后被初始化?如果您让他们调用一个返回映射引用的静态函数,那么它可以在第一次调用时对其进行初始化。使映射成为其中的静态局部变量函数,您可以在没有此保护的情况下停止任何意外使用。

您不需要假类……您可以使用lambda进行初始化

auto myMap = []{
    std::map<int, string> m;
    m["test"] = 222;
    return m;
}();
automymap=[]{
std::map m;
m[“测试”]=222;
返回m;
}();
或者,如果只是普通数据,则初始化映射:

std::map<std::string, int> myMap { { "test", 222 } };
std::map myMap{{“test”,222};
使用下面的复杂代码是一个好主意吗(例如) 做一些std::map操作

没有


任何一种解决可变非局部变量的解决方案都是一个可怕的想法。

< P>你所做的是完全合法的C++。所以,如果它对你有用,并且是可以被其他人使用代码理解和理解的,那就没问题。Joachim Pileborg的例子对我来说更清楚。< /P> 初始化全局变量时,如果它们在初始化期间相互使用,则可能会出现这样的问题。在这种情况下,确保变量以正确的顺序初始化可能会很棘手。因此,我更喜欢创建InitializeX、InitializeY等函数,并从主函数显式地以正确的顺序调用它们行动

错误的顺序也会导致程序退出时出现问题,全局变量在其中一些可能已被销毁的情况下仍试图相互使用。同样,在主返回之前以正确顺序进行一些显式销毁调用可以使问题更清楚

<>所以,如果它对你有用,那就去注意它。同样的建议也适用于C++中的每个特性!

你在问题中说你自己认为代码是“棘手的”。没有必要为了它而使事情过于复杂。因此,如果你有一个对你来说不那么“棘手”的替代方案……那可能会更好。

当我听到“棘手的代码”时我立刻想到代码气味和维护噩梦。回答你的问题,不,这不是一个好主意。虽然它是有效的C++代码,但却是一个很差的实践。还有其他更明确和有意义的替代方案来解决这个问题。方法返回void*NULL对于程序的意图来说是毫无意义的(即,代码的每一行都应该有意义的目的),现在您还有另一个不必要的全局变量fakeVar,它不必要地指向NULL

让我们考虑一些“棘手”的替代方案:

  • 如果您只有一个myMap的全局实例这一点非常重要,那么使用单例模式可能更合适,并且您可以在需要时懒洋洋地初始化myMap的内容。请记住,单例模式本身也有问题

  • 使用静态方法创建并返回映射或使用全局名称空间。例如,以下内容:

    // global.h
    namespace Global
    {
        extern std::map<std::string, int> myMap;
    };
    
    // global.cpp
    namespace Global
    {
        std::map<std::string, int> initMap()
        {
            std::map<std::string, int> map;
            map["test"] = 222;
            return map;
        }
    
        std::map<std::string, int> myMap = initMap();
    };
    
    // main.cpp
    #include "global.h"
    
    int main()
    {
       std::cout << Global::myMap.size() << std::endl;
       return 0;
    }
    
    //global.h
    命名空间全局
    {
    外部std::map myMap;
    };
    //global.cpp
    命名空间全局
    {
    std::map initMap()
    {
    地图;
    map[“测试”]=222;
    返回图;
    }
    std::map myMap=initMap();
    };
    //main.cpp
    #包括“global.h”
    int main()
    {
    
    std::cout在这种情况下,unity构建(单个翻译单元构建)可能非常强大。
    \uuuu COUNTER\uuuuu
    宏是事实上的标准
    class MyMap
    {
    private:
        std::map<std::string, int> map;
    
    public:
    
        MyMap()
        {
            map["test"] = 222;
        }
    
        void put(std::string key, int value)
        {
            map[key] = value;
        }
    
        unsigned int size() const
        {
            return map.size();
        }
    
        // Overload operator[] and create any other methods you need
        // ...
    };
    
    MyMap myMap;
    
    int main()
    {
       std::cout << myMap.size() << std::endl;
       return 0;
    }
    
    // At the beginning of the file...
    template <uint64_t N> void global_function() { global_function<N - 1>(); } // This default-case skips "gaps" in the specializations, in case __COUNTER__ is used for some other purpose.
    template <> void global_function<__COUNTER__>() {} // This is the base case.
    
    void run_global_functions();
    
    #define global_n(N, ...) \
    template <> void global_function<N>() { \
        global_function<N - 1>(); /* Recurse and call the previous specialization */ \
        __VA_ARGS__; /* Run the user code. */ \
    }
    #define global(...) global_n(__COUNTER__, __VA_ARGS__)
    
    // ...
    
    std::map<std::string, int> myMap;
    
    global({
        myMap["test"]=222;
        // Do whatever with your global variables
    })
    global(myMap["Error"] = 111);
    
    int main() {
        run_global_functions();
        std::cout << "Map size: " << myMap.size() << std::endl; // Show myMap has initialized correctly :)
    }
    
    global(std::cout << "This will be the last global code run before main!");
    
    
    // ...At the end of the file
    
    void run_global_functions() {
        global_function<__COUNTER__ - 1>();
    }
    
    // At the beginning of the file...
    extern bool has_static_init;
    #define default_construct(x) x{}; global(if (!has_static_init()) new (&x) decltype(x){})
    // Or if you don't want placement new:
    // #define default_construct(x) x{}; global(if (!has_static_init()) x = decltype(x){})
    
    class Complicated {
        int x = 42;
        Complicated() { std::cout << "Constructor!"; }
    }
    Complicated default_construct(my_complicated_instance); // Will be zero-initialized if the CRT is not linked into the program.
    
    int main() {
        run_global_functions();
    }
    
    // ...At the end of the file
    static bool get_static_init() {
        volatile bool result = true; // This function can't be inlined, so the CRT *must* run it.
        return result;
    }
    has_static_init = get_static_init(); // Will stay zero without CRT
    
    #include <functional>
    
    auto initializer = std::invoke([]() {
        // Do initialization here...
    
        // The following return statement is arbitrary. Without something like it,
        // the auto will resolve to void, which will not compile:
        return true;
    });