【问题标题】:Having Ref object as class member将 Ref 对象作为类成员
【发布时间】:2019-04-09 00:15:12
【问题描述】:

我希望通过引用将我的数据传递给一个类,其中引用本身应该是公共变量,以供成员函数访问。如果我声明我的类及其构造函数

class max_likelihood { 
public: 
MatrixXd dat
max_likelihood(const Ref<const MatrixXd>& dat_in)
{dat = dat_in;}

我得到了正常运行的代码,但最终创建了dat 的副本,我想避免这种情况。

我尝试过这样做:

class max_likelihood {
public:
const Ref<const MatrixXd>& dat;
max_likelihood(const Ref<const MatrixXd>& dat){}

但这不起作用和/或不允许我访问对dat 的引用,甚至无法编译。

根据我的研究,我从question 中找到了这一点

如果你想重新分配一个 Ref 来引用另一个缓冲区,那么使用一个placement new 来重新调用 Ref 的构造函数。不要忘记先调用析构函数。

我相信这可能有助于回答我的问题,但我不知道这些说明在实践中意味着什么,因此我的问题在这里。具体来说,我想我正在创建一个 Ref 对象的新实例来传递传递的引用。当源数据在别处创建时,例如通过 main 从文件中读取,我如何解释这个答案或找到更优雅的方式在类中使用 Ref 对象?

【问题讨论】:

  • 您是否考虑过更改max_likelihood 以按值获取参数或添加通过右值引用获取参数的重载?在不需要的情况下,您可以避免复制。
  • 使用placement new 不会为您保存副本。链接的问题是朝着错误的方向发展。
  • 请分享minimal reproducible example 以更好地说明用例。
  • 不要把事情复杂化,使用移动语义
  • @FrançoisAndrieux Ref 是由库 Eigen eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html 提供的类

标签: c++ memory-management reference eigen


【解决方案1】:

你可以使用初始化列表:

struct max_likelihood { 
    MatrixXd& dat
    max_likelihood(MatrixXd& dat_in) : dat(dat_in) {}
};

【讨论】:

    【解决方案2】:

    成员变量dat是一个需要初始化的const引用。

    max_likelihood(const Ref<const MatrixXd>& argdat):dat(argdat){}
    

    您可能希望使用非 const ref:

    class max_likelihood {
    public:
    Ref<const MatrixXd> dat;
    max_likelihood(const Ref<const MatrixXd>& dat):dat(argdat){}
    

    至少你得到一个本地参考。

    【讨论】:

    • 这个解决方案太危险了,我不认为 OP 理解所有含义。
    • 去掉了 const Ref&,我同意它没用,会更慢,可能会崩溃。
    • @Slava 很可能是的,所以我正要写一个例子,但认为我的 q 足够微不足道,可以当场解决。我试图在我的标题中将 dat 预先声明为 MatrixXd(生成副本)或作为参考。这就是您的意思以及该解决方案的作用吗?或者评论是对的。 :-)
    • @Hirek 获取 const 引用并保持它是容易出错的解决方案 - 例如,您可以轻松传递临时引用并获得悬空引用。一般来说 - 在类中引用(无论是否为 const)并不是一个好主意。
    • @Slava 好的所以你实际上是说在这种情况下最好通过值传递,即将物理数据交给类(然后我想在内部通过引用传递)就在风格方面?
    【解决方案3】:

    我得到了正常运行的代码,但最终创建了 dat 的副本,我想避免这种情况。

    在这种情况下使用引用来避免数据复制是一个糟糕的想法,在类中维护引用会使事情变得相当复杂。因此,如果 MatrixXd 为 C++11 或更高版本正确设计,只需使用移动语义:

    class max_likelihood { 
    public: 
       MatrixXd dat;
       max_likelihood(MatrixXd dat_in) : dat( std::move(dat_in) ) {}
       ...
    };
    

    如果不动态分配并转移所有权:

    class max_likelihood {  
    public: 
       std::unique_ptr<MatrixXd> dat;
       max_likelihood(std::unique_ptr<MatrixXd> dat_in) : dat( std::move(dat_in) ) {}
       ...
    };
    

    通常在类中引用不是一个好主意,首先您需要小心不要获得悬空引用,其次 - 如果您决定允许复制和/或分配对象,您将遇到麻烦。

    【讨论】:

    • 阅读一下这个问题我认为这是一个很好的解决方案。如果除了 dat 之外我还有更多参数,那么它的语法会像继承的语法一样,即用逗号分隔吗?
    • 这个答案非常愚蠢,因为可以在不使用移动语义的情况下完成完全相同的事情,而是将 MatrixXd& 的引用存储为成员(并避免复制相同,并且没有问题如果对 MatrixXd 对象正确使用 RAII,则悬空引用。)使用 Eigen::Ref 的真正原因是允许您的代码将一般 Eigen 类型作为输入(有关详细信息,请参阅 Eigen 文档。)
    【解决方案4】:

    您可以像这样设置和访问参考:

    class max_likelihood {
    public:
       max_likelihood( const MatrixXd& input_dat): dat(input_dat) { }
       const MatrixXd& dat;
    };
    

    但是您不能更改引用,即将它重新分配给另一个对象来引用。

    如果您需要这个功能,那么您必须将成员变量更改为指针,然后您可以轻松更改指针。如果您不希望您的类的用户必须使用指针,您可以添加一个返回引用的方法。

    如果您实现了指针解决方案,请记住,只要 anypody 尝试使用您的 max_likelihood 类访问它,原始对象就必须保持不变。也许您应该使用std::shared_ptr&lt;&gt; 来防止内存泄漏。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-10
      • 2018-06-10
      • 1970-01-01
      • 2012-10-29
      • 2015-04-03
      相关资源
      最近更新 更多