如何在无动态内存与冗余拷贝下将Table从工厂传给Scheme构造函数?
无动态内存分配的Runge-Kutta Scheme构造方案问题
背景
龙格-库塔格式(Runge-Kutta schemes)由实现于Scheme类的算法,以及名为Table(布彻表,Butcher tableau)的数据组成。我们希望用户仅通过如下语法构造Scheme实例:
Scheme s = Factory::makeSchemeXY();
其中XY标识该格式所使用的特定Table,且Scheme不允许其他构造方式。
当前实现采用表达式模板设计模式,将Table作为表达式模板。由于Table数据量可能极大,示例中使用shared_ptr避免不必要的拷贝与销毁,代码如下:
#include<iostream> #include<memory> class Table; class Factory; class Scheme; class Table{ friend class Factory; friend class Scheme; double A=0; Table(){} public: ~Table(){std::cout<<"~Table\n";} // only one table is used, hence avoid instantiation of copy }; class Scheme{ std::shared_ptr<Table> pt; friend class Factory; Scheme()=delete; void operator=(Scheme const&)=delete; public: Scheme(std::shared_ptr<Table> pt):pt(pt){} }; struct Factory{ Factory()=delete; static std::shared_ptr<Table> makeSchemeXY(){ std::shared_ptr<Table> p( new Table ); // heap allocation won't work on some platforms p->A = 42; // the table should be constructed here, not in the scheme. That would become too messy. return p; // can't we use std::move, or elision, or something here? } }; struct App{ Scheme x = Factory::makeScheme(); // <--- highly preferred consumer syntax }; int main(){ App a; }
核心问题
我们希望在工厂函数中构造Table并将其作为Scheme的成员存储,但上述实现依赖动态内存分配,无法适配部分嵌入式平台。如何实现无需动态内存分配、也无冗余拷贝的方案?
已尝试方案及问题
- 让
makeScheme返回Table对象,Scheme持有Table类型成员,期望触发拷贝消除,但实际触发两次~Table调用,说明存在冗余拷贝; - 在
makeScheme的返回语句和Scheme的构造函数初始化列表中使用std::move(t),但Table仍会在两处构造,产生两个实例。
以下是包含拷贝消除与移动语义尝试的代码示例(当前未注释部分可编译,但会触发两次Table实例化):
#include<iostream> class Table; class Factory; class Scheme; class Table{ friend class Factory; friend class Scheme; double A=0; Table(){} public: ~Table(){std::cout<<"~Table\n";} }; class Scheme{ friend class Factory; Scheme()=delete; void operator=(Scheme const&)=delete; // Table t; public: Scheme(Table t):t(t){} // hope for elision //Scheme(Table&& t):t(std::move(t)){} // using move }; struct Factory{ Factory()=delete; static Table makeScheme(){ Table t; t.A=2; return t; } // hope for elision //static Table makeScheme(){ Table t; t.A=2; return std::move(t); } //static Table&& makeScheme(){ Table t; t.A=2; return std::move(t); } // pardon my futile attempt }; struct App{ Scheme x = Factory::makeScheme(); }; int main(){ App a; }
备注
尽管Table逻辑上应设为const,但所使用的BLAS接口不支持const类型,因此Scheme中的Table需为非const(实际不会对其进行修改)。
内容的提问来源于stack exchange,提问作者GRamon
相关产品推荐
相关产品推荐

