为什么我不能从构造函数初始化ifstream引用?

时间:2018-05-18 18:39:44

标签: c++

我正在尝试从构造函数初始化std :: ifstream引用,但是我收到错误说

invalid initialization of reference of type ‘std::ifstream& {aka std::basic_ifstream<char>&}’ from expression of type ‘const string {aka const std::__cxx11::basic_string<char>}’
  A(const std::string& file_name):inFile(file_name){}

以下是代码

#include <string>
#include <fstream>

class A{
  public:
    A(const std::string& file_name):inFile(file_name){}

  private:
    std::ifstream& inFile;
};

int main(){
  A("text.txt");
}

1 个答案:

答案 0 :(得分:6)

问题

class A{
public:
 A(const std::string& file_name):inFile(file_name){}

private:
 std::ifstream& inFile;
};
必须初始化

inFile以引用现有的istreaminFile(file_name)不会构建istream;它会尝试inFile引用string。编译器无法正常工作并发出错误。

上述说明

inFile不是ifstreamIt is a reference,一个别名,变量为ifstream的变量。您无法构建引用,因为没有任何内容可以构造。它只是已存在的变量的新名称。必须构造引用的变量。

为什么这适用于int

如果你

class A{
  public:
    A(int & an_Int):int_Ref(an_Int){}

  private:
    int & int_Ref;
};

int_Ref是指int所指的an_Int。如果相反,你

A(int an_int):int_Ref(an_int){} 

它仍然会编译,但是你有一个问题因为int_Ref引用an_int,这是一个作用于构造函数的自动变量。当你使用an_int进行任何操作时,A已经死了,可能会被埋葬。使用int_Ref将是Undefined Behaviour,并且由于行为未定义,所以可能发生任何事情,包括您期望的行为。在蚱蜢打喷嚏并且程序突然停止正常工作之前,这可能会让你长时间愚弄。事实上,从未正常工作。

A(const std::string& file_name):intRef(file_name){}

由于int引用无法引用std::string,因此无法正常工作。

解决方案

有两个合理的选择:

选项1

class A{
public:
 A(const std::string& file_name):inFile(file_name){}

private:
 std::ifstream inFile; // no longer a reference
};

将在istream的实例中为指定文件构建A

选项2

class A{
public:
 A(std::ifstream & in):inFile(in){} // accepts ifstream reference, not string reference

private:
 std::ifstream & inFile; 
};

初始化inFile以引用ifstream引用的给定预先存在的in。这意味着

int main(){
  A("text.txt");

}

必须成为

int main(){
  std::ifstream in("text.txt");
  A(in);

}

需要注意的是,提供给ifstream的{​​{1}}的生命周期必须大于A实例的生命周期。这意味着

A

是一个死亡陷阱。返回的A ABuilder(const std::string& file_name) { std::ifstream in(file_name); return A(in); } 包含对不再存在的对象的引用。

由于选项2出错的可能性增加,我建议更喜欢选项1