【问题标题】:Defining class member via a reference passed through constructor通过构造函数传递的引用定义类成员
【发布时间】:2016-10-21 22:15:42
【问题描述】:

我正在研究 C++ 中的链表实现,我对原始数据的生命周期感到好奇。假设一个调用程序使用以下构造函数创建一个新的 ListNode。我担心的是,如果数据成员分配不是值的副本,原始变量可能会超出范围而留下未定义的行为。

ListNode<T>::ListNode(const T &value) : data(value) {}

当值传递给参数列表中的数据时,它会将数据定义为值的副本还是将类成员链接到传递给构造函数的原始变量?

编辑:为清楚起见添加更多信息

list_node.hpp

template <typename T>
class ListNode
{

friend class List<T>;

public:
   ListNode<T>(const T &);

private:
   T data;

};

list.hpp

template<typename T>
class List
{
public:
   void insert_at_front(const T &);
private:
   ListNode<T> *get_new_node(const T &);
};

list.cpp

void List<T>::insert_at_front(const T &value)
{
   ListNode<T> *new_node_ptr = get_new_node(value);

   ...
}

ListNode<T> *List<T>::get_new_node(const T &value)
{
   return new ListNode<T>(value);
}

【问题讨论】:

  • 取决于data的类型。
  • 如果你想要一个副本,那么你应该按值传递,而不是通过引用传递。但当然,如果 data 是一个参考,那也无济于事。
  • 意思是发布data的声明。
  • @MarkRansom 这里没有理由按值传递。如果你不关心性能,这很好,你不需要打电话给std::move。如果你关心性能,你应该有 const&amp;&amp;&amp; 重载无论如何更快。
  • @Nir Friedman:当你确定需要一个副本时,通过值传递然后执行std::move 在性能方面非常好,并且省去了编写多个重载的麻烦。确实可以通过编写这些重载来从中获得更多性能。但是说“传值然后移动”的方法意味着“不关心性能”远不准确。

标签: c++ pass-by-reference assignment-operator class-members


【解决方案1】:
struct Foo {
    Foo(const Bar& b) : m_b(b) {}

    Bar m_b;    
};

struct Foo2 {
    Foo2(const Bar& b) : m_b(b) {}

    const Bar& m_b;    
};

如您所见,构造函数代码是相同的,但是这两个类做的事情不同。第一个类将复制传递的Bar,因此如果传入的局部变量超出范围,它是“安全的”。第二类只是获取参考。实际上,这就像持有对传入变量的引用。因此,如果传入的变量超出范围,那么Foo2 将有一个悬空引用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-19
    • 1970-01-01
    • 1970-01-01
    • 2020-08-05
    • 1970-01-01
    • 2020-02-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多