2013-10-04 48 views
2

我有一个包含大型数据表的类,它具有一个构造函数,该构造函数获取计算该数据所需的所有参数。但是,它需要很长时间才能运行,所以我添加了一个构造函数,它接收一个流,并从该流中读取数据。虽然我有一个设计这个类的RAII方法,但我遇到了麻烦,因为我有两个构造函数,并且在运行时我需要在它们之间进行选择。这是我想出的:RAII在两个构造函数之间进行选择

std::string filename; // Populated by command line arguments 
DataTable table; // Empty constructor, no resource acquisition or initialization 

if(filename.empty()) { 
    table = DataTable(/*various parameters*/); 
} else { 
    std::ifstream filestream(filename); 

    table = DataTable(filestream); // Reads from file 
} 

这对我来说很脆弱。默认的构造函数将使对象保持有效状态,但是没用。它的唯一用处是在外部范围中创建一个“临时”对象,将其分配给if语句的其中一个分支。另外,在后台有一个“插入”标志来管理对象是默认构建还是完全初始化。有没有更好的方法来设计这个类?

回答

4

也许是这样的:

DataTable foo = filename.empty() 
       ? DataTable(x, y, z) 
       : DataTable(std::ifstream(filename)); 
+0

这是正确的做法。如果他这样做,他可能会想要添加一个移动构造函数,当然,只有当他具有C++ 11时才会起作用。 (他将无法将临时ifstream绑定到std :: istream,他需要使用像std :: ifstream(filename).seekg(0,std :: ios_base: :beg)'。或者,如果构造函数具有C++ 11,那么它的构造函数也需要右值引用。) –

0

将文件测试代码移动到ctor中,将ctors移动到两个私人函数中,从ctor调用其中一个函数,或者在所有内容都失败时抛出异常。

0

的几点思考:

  1. 摆脱 “inited” 标志。
  2. 摆脱默认的构造函数,如果不能明智地构造对象
  3. 使用这种结构的让你一个DataTable

    DataTable get_me_my_data_fool(ParameterTypes... params, const string& filename = "") 
    { 
        if(!filename.empty()) 
        return DataTable(std::ifstream(filename)); // check if file exists! 
        else 
        return DataTable(params...); 
    } 
    

其实,现在我想想它,最好把这个逻辑放入DataTable的构造函数中。

0

如果该类支持拷贝,然后Kerrek SB的解决方案是要走的路 。然而,从你说的话来看,复制是昂贵的。在 这种情况下,你可以使用C++ 11,你可以尝试添加一个移动 的构造函数,以避免深度复制。否则,你可能 卡动态分配:

std::auto_ptr<DataTable> fooPtr(filename.empty() 
           ? new DataTable(x, y z) 
           : new DataTable(filename)); 
DataTable& foo = *fooPtr; 
0

这里的另一个想法完整性的考虑:

template<typename T> 
class uninitialised 
{ 
public: 
    ~uninitialised() 
    { 
     if (alive_) { 
      operator T&().~T(); 
     } 
    } 

    template<typename... Ts> 
    void create(Ts&&... args) 
    { 
     assert(!alive_ && "create must only be called once"); 
     void* const p = obj_; 
     ::new(p) T(std::forward<Ts>(args)...); 
     alive_ = true; 
    } 

    operator T&() 
    { 
     assert(alive_ && "T has not been created yet"); 
     return *reinterpret_cast<T*>(obj_); 
    } 

private: 
    bool alive_ = false; 
    alignas(T) unsigned char obj_[sizeof(T)]; 
}; 

// ... 

std::string filename; 
uninitialised<DataTable> table; 

if (filename.empty()) { 
    table.create(/* various parameters */); 
} else { 
    std::ifstream filestream(filename); 
    table.create(filestream); 
} 

DataTable& tbl = table; 
相关问题