首页 > 解决方案 > 为什么我不能从构造函数初始化 ifstream ref?

问题描述

我正在尝试从构造函数初始化 std::ifstream ref,但我收到一条错误消息

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");
}

标签: c++

解决方案


问题

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

private:
 std::ifstream& inFile;
};

inFile必须初始化以引用现有的istream. inFile(file_name)不构造istream; 它试图inFile引用一个string. 编译器无法使其工作并发出错误。

上面的解释

inFile不是一个ifstream它是对一个变量的引用、别名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 Behavior,并且由于行为未定义,任何事情都可能发生,包括您期望的行为。在蚱蜢打喷嚏并且程序突然停止正常工作之前,这可能会欺骗您很长时间。事实上,它从未正常工作过。

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
};

它将istreamA.

选项 2

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

private:
 std::ifstream & inFile; 
};

它初始化inFile以引用由 引用的给定的预先存在ifstreamin。这意味着

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

}

必须成为

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

}

这伴随着一个警告,即ifstream提供的 toA必须具有比A. 这意味着

A ABuilder(const std::string& file_name)
{
    std::ifstream in(file_name);
    return A(in);
}

是一个死亡陷阱。返回的A包含对不再存在的对象的引用。

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


推荐阅读