在同一个类的静态函数中创建类的实例是未定义的行为吗 我的搜索在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案例的问题。我敢打赌,您遇到的问题并不是因为在这里创建类类型的对象。你能用一个复制行为所需的最小示例发布一个后续问题吗?我敢打赌,你遇到的问题并不是因为在这里创建类类型的对象。你能用一个迷你们贴一个后续问题吗 复制这种行为需要错误的例子吗?