在同一个类的静态函数中创建类的实例是未定义的行为吗 我的搜索在C++解决方案方面几乎没有取得什么成果… 我有一个从配置文件中获取信息的类,我有一个从不同的配置文件中获取站点号的静态函数。为了避免重复代码,我在静态函数中创建了一个类的实例。使用-Wall编译时不会出现任何警告

在同一个类的静态函数中创建类的实例是未定义的行为吗 我的搜索在C++解决方案方面几乎没有取得什么成果… 我有一个从配置文件中获取信息的类,我有一个从不同的配置文件中获取站点号的静态函数。为了避免重复代码,我在静态函数中创建了一个类的实例。使用-Wall编译时不会出现任何警告,c++,c++03,C++,C++03,不幸的是,我找不到任何关于它是否是未定义行为的信息。是吗 #include <iostream> #include <fstream> #include "srxDSLog.H" extern SrxDsLog *Logger; class Stanza { private: std::string config_file_path_; public: Stanza(std::string config_file_path) {

不幸的是,我找不到任何关于它是否是未定义行为的信息。是吗

#include <iostream>
#include <fstream>
#include "srxDSLog.H"

extern  SrxDsLog *Logger;

class Stanza {
private:
    std::string config_file_path_;

public:
    Stanza(std::string config_file_path) { 
        config_file_path_ = config_file_path;
    }

    std::string GetValue(std::string config_section, std::string config_setting) {
        std::ifstream config_file(config_file_path_.c_str(), std::ios::in);
        std::string current_section, line;
        for ( ; std::getline(config_file, line); ) {
            line = rtrim(line);
            if (line.find(" ") == std::string::npos && line.find(":") != std::string::npos) {
                current_section = line.substr(0, line.find(":"));
                continue;
            }
            if (current_section == config_section) {
                if (line.find(config_setting) != std::string::npos && line.find("=") != std::string::npos) {
                    return line.substr(line.find(config_setting) + config_setting.length() + 3); // we're getting the string starting after the name of the setting + " = " + 1. We're assuming there's exactly 1 space 
                }
            }
        }
        if (current_section.empty()) {
            Logger->WriteLog("Couldn't find section: " + config_section, LOG_ERROR, "Stanza::GetValue");
            return "";
        }
        else {
            Logger->WriteLog("Couldn't find setting: " + config_setting, LOG_ERROR, "Stanza::GetValue");
            return "";
        }
        Logger->WriteLog("Somehow reached the end of function without returning", LOG_ERROR, "Stanza::GetValue");
        return "";
    }

    static std::string rtrim(std::string input) {
        if (input.find_last_not_of(" ") == input.length() - 1) {
            return input;
        }
        else {
            return input.substr(0, input.find_last_not_of(" ") + 1);
        }
    }

    static int GetStoreNumber() {
        Stanza store_config("/u/data/store.cfg");
        std::string store_number =  store_config.GetValue("store", "site");
        return atoi(store_number.c_str());
    }

};

这是完全可以接受的代码。我不能告诉你一个参考文献说这不是未定义的行为,因为这不是一个任何人都认为令人担忧的案例

静态函数就像普通的友元函数一样,不在类内部。如果您能够在普通的无关函数中创建对象,那么您也应该能够在静态函数中创建对象


举个例子,我有静态函数,它们在生活中的全部目的就是构造我的类的成员。我使用这些来确保我的类的所有实例都是使用new构造的,并且通过shared_ptr引用

这是完全可以接受的代码。我不能告诉你一个参考文献说这不是未定义的行为,因为这不是一个任何人都认为令人担忧的案例

静态函数就像普通的友元函数一样,不在类内部。如果您能够在普通的无关函数中创建对象,那么您也应该能够在静态函数中创建对象


举个例子,我有静态函数,它们在生活中的全部目的就是构造我的类的成员。我使用这些来确保我的类的所有实例都是使用new构造的,并且通过shared_ptr引用

这是完全合法和完全安全的

有时,将静态函数视为自由函数会有所帮助,因为它恰好位于声明它的类的内部。您可以在自由函数中声明Stanza类型的对象,所以在Stanza内部的静态成员函数中声明也可以


在很少的情况下,在T的成员函数中定义T类型的对象是有风险的,这些情况主要是构造函数或析构函数,您必须担心意外递归。

这是完全合法的,也是完全安全的

有时,将静态函数视为自由函数会有所帮助,因为它恰好位于声明它的类的内部。您可以在自由函数中声明Stanza类型的对象,所以在Stanza内部的静态成员函数中声明也可以

在很少的情况下,在T的成员函数中定义T类型的对象是有风险的,这些情况主要是构造函数或析构函数,您必须担心意外递归

不幸的是,我找不到任何关于它是否是未定义行为的信息。是吗

#include <iostream>
#include <fstream>
#include "srxDSLog.H"

extern  SrxDsLog *Logger;

class Stanza {
private:
    std::string config_file_path_;

public:
    Stanza(std::string config_file_path) { 
        config_file_path_ = config_file_path;
    }

    std::string GetValue(std::string config_section, std::string config_setting) {
        std::ifstream config_file(config_file_path_.c_str(), std::ios::in);
        std::string current_section, line;
        for ( ; std::getline(config_file, line); ) {
            line = rtrim(line);
            if (line.find(" ") == std::string::npos && line.find(":") != std::string::npos) {
                current_section = line.substr(0, line.find(":"));
                continue;
            }
            if (current_section == config_section) {
                if (line.find(config_setting) != std::string::npos && line.find("=") != std::string::npos) {
                    return line.substr(line.find(config_setting) + config_setting.length() + 3); // we're getting the string starting after the name of the setting + " = " + 1. We're assuming there's exactly 1 space 
                }
            }
        }
        if (current_section.empty()) {
            Logger->WriteLog("Couldn't find section: " + config_section, LOG_ERROR, "Stanza::GetValue");
            return "";
        }
        else {
            Logger->WriteLog("Couldn't find setting: " + config_setting, LOG_ERROR, "Stanza::GetValue");
            return "";
        }
        Logger->WriteLog("Somehow reached the end of function without returning", LOG_ERROR, "Stanza::GetValue");
        return "";
    }

    static std::string rtrim(std::string input) {
        if (input.find_last_not_of(" ") == input.length() - 1) {
            return input;
        }
        else {
            return input.substr(0, input.find_last_not_of(" ") + 1);
        }
    }

    static int GetStoreNumber() {
        Stanza store_config("/u/data/store.cfg");
        std::string store_number =  store_config.GetValue("store", "site");
        return atoi(store_number.c_str());
    }

};
就函数的行为而言,这是非常好的

我不清楚的是,在静态成员函数中是否需要该类的非静态实例

如果在程序执行期间/u/data/store.cfg文件的内容预计不会更改,则可以使用静态变量

static int GetStoreNumber() {
    static Stanza store_config("/u/data/store.cfg");
    std::string store_number =  store_config.GetValue("store", "site");
    return atoi(store_number.c_str());
}
您可以进一步细化它以使用:

static int GetStoreNumber() {
    static int number = getStoreNumber("/u/data/store.cfg");
    return number;
}

static int GetStoreNumber(std::strinc const& filename) {
    Stanza store_config(filename);
    std::string store_number =  store_config.GetValue("store", "site");
    return atoi(store_number.c_str());
}
如果在程序执行期间/u/data/store.cfg文件的内容预计会发生更改,则可以保留现有函数

不幸的是,我找不到任何关于它是否是未定义行为的信息。是吗

#include <iostream>
#include <fstream>
#include "srxDSLog.H"

extern  SrxDsLog *Logger;

class Stanza {
private:
    std::string config_file_path_;

public:
    Stanza(std::string config_file_path) { 
        config_file_path_ = config_file_path;
    }

    std::string GetValue(std::string config_section, std::string config_setting) {
        std::ifstream config_file(config_file_path_.c_str(), std::ios::in);
        std::string current_section, line;
        for ( ; std::getline(config_file, line); ) {
            line = rtrim(line);
            if (line.find(" ") == std::string::npos && line.find(":") != std::string::npos) {
                current_section = line.substr(0, line.find(":"));
                continue;
            }
            if (current_section == config_section) {
                if (line.find(config_setting) != std::string::npos && line.find("=") != std::string::npos) {
                    return line.substr(line.find(config_setting) + config_setting.length() + 3); // we're getting the string starting after the name of the setting + " = " + 1. We're assuming there's exactly 1 space 
                }
            }
        }
        if (current_section.empty()) {
            Logger->WriteLog("Couldn't find section: " + config_section, LOG_ERROR, "Stanza::GetValue");
            return "";
        }
        else {
            Logger->WriteLog("Couldn't find setting: " + config_setting, LOG_ERROR, "Stanza::GetValue");
            return "";
        }
        Logger->WriteLog("Somehow reached the end of function without returning", LOG_ERROR, "Stanza::GetValue");
        return "";
    }

    static std::string rtrim(std::string input) {
        if (input.find_last_not_of(" ") == input.length() - 1) {
            return input;
        }
        else {
            return input.substr(0, input.find_last_not_of(" ") + 1);
        }
    }

    static int GetStoreNumber() {
        Stanza store_config("/u/data/store.cfg");
        std::string store_number =  store_config.GetValue("store", "site");
        return atoi(store_number.c_str());
    }

};
就函数的行为而言,这是非常好的

我不清楚的是,在静态成员函数中是否需要该类的非静态实例

如果在程序执行期间/u/data/store.cfg文件的内容预计不会更改,则可以使用静态变量

static int GetStoreNumber() {
    static Stanza store_config("/u/data/store.cfg");
    std::string store_number =  store_config.GetValue("store", "site");
    return atoi(store_number.c_str());
}
您可以进一步细化它以使用:

static int GetStoreNumber() {
    static int number = getStoreNumber("/u/data/store.cfg");
    return number;
}

static int GetStoreNumber(std::strinc const& filename) {
    Stanza store_config(filename);
    std::string store_number =  store_config.GetValue("store", "site");
    return atoi(store_number.c_str());
}

如果在程序执行过程中/u/data/store.cfg文件的内容会发生变化,您可以保留现有的功能。

我认为这在工厂模式中是相当典型的,这进一步说明它是完全定义的,因为它通常使用我认为这在工厂模式中是相当典型的,还有一点是它被完全定义了,因为它通常是出于好奇,有没有理由认为这不安全?我担心C++的未来,很快人们就会问,在函数中创建int变量是否正确。我的最后一个问题以未定义的行为结束,因为我做了一些我见过很多次的事情,但在C++11之前显然没有定义。在构造函数内部调用构造函数。这导致了一种极其怪异的行为。我只是在互联网上找不到任何东西,我能找到的只是“我能在另一个类中实例化一个类吗?”或者answe
从Perl或java……@ XyOy中,您可以在C++中从另一个调用一个构造函数…检查这个问题:我有一个默认构造函数,它有4个参数,是从2个不同的构造函数调用的,得到3个参数。没有来自GCC的警告,只是一个完全无关的函数不会写入文件。现在我改变了构造函数,只使用了1个构造函数,所有的东西都起作用了。出于好奇,你有没有理由认为这不安全?我担心C++的未来。很快人们就会问,在函数中创建int变量是否正确。我的最后一个问题以未定义的行为结束,因为我做了一些我见过很多次的事情,但在C++11之前显然没有定义。在构造函数内部调用构造函数。这导致了一种极其怪异的行为。我只是在网上找不到任何东西,我能找到的是“我能在不同的类中实例化一个类吗?”或者从Perl或java……C++中回答。检查这个问题:我有一个默认构造函数,它有4个参数,是从2个不同的构造函数调用的,得到3个参数。没有来自GCC的警告,只是一个完全无关的函数不会写入文件。现在我改变了构造函数,只使用了1个构造函数,一切都正常。任何复杂的静态变量都可以在程序启动之前引入有趣的初始化周期。有时这些甚至可以包括周期。如果其他初始化例程出于某种原因调用GetStoreNumber,例如,而节依赖于此其他初始化例程才能工作。@Omnifarious,我不明白您的意思。例如,假设该节在构造时在其构造函数中调用GetStoreNumber。假设它正在从模板初始化商店名称,模板调用了商店的编号。然后,构造一个节将导致无限递归。当然,这不是特定于静态的。但是,假设您在具有静态实例的某个其他类的构造函数中需要Stanza::GetStoreNumber,而Stanza的构造函数需要这个静态类而不是这个其他类。然后,基本上在启动时就有一个初始化周期。如果你仔细地分层设计,这样一个周期就不会发生,静态初始化一个原语类型的向量就可以了,例如,因为它不会调用你的代码,那么你就可以了。但是,如果您担心是否可以在该类的静态成员函数中声明该类的实例,那么我不确定您的设计是否正确分层以避免循环。由于这个原因,我不喜欢静态初始化非POD变量。@Omnifarious,感谢您花时间详细解释您的观点。是的,我现在明白你的担心了。希望对于OP来说这不是问题。任何复杂的静态变量都可以在程序启动之前引入有趣的初始化周期。有时这些甚至可以包括周期。如果其他初始化例程出于某种原因调用GetStoreNumber,例如,而节依赖于此其他初始化例程才能工作。@Omnifarious,我不明白您的意思。例如,假设该节在构造时在其构造函数中调用GetStoreNumber。假设它正在从模板初始化商店名称,模板调用了商店的编号。然后,构造一个节将导致无限递归。当然,这不是特定于静态的。但是,假设您在具有静态实例的某个其他类的构造函数中需要Stanza::GetStoreNumber,而Stanza的构造函数需要这个静态类而不是这个其他类。然后,基本上在启动时就有一个初始化周期。如果你仔细地分层设计,这样一个周期就不会发生,静态初始化一个原语类型的向量就可以了,例如,因为它不会调用你的代码,那么你就可以了。但是,如果您担心是否可以在该类的静态成员函数中声明该类的实例,那么我不确定您的设计是否正确分层以避免循环。由于这个原因,我不喜欢静态初始化非POD变量。@Omnifarious,感谢您花时间详细解释您的观点。是的,我现在明白你的担心了。希望这不是OP案例的问题。我敢打赌,您遇到的问题并不是因为在这里创建类类型的对象。你能用一个复制行为所需的最小示例发布一个后续问题吗?我敢打赌,你遇到的问题并不是因为在这里创建类类型的对象。你能用一个迷你们贴一个后续问题吗 复制这种行为需要错误的例子吗?