std::列表< std::unique_ptr; >:传递它

发布于 2024-09-09 03:47:40 字数 680 浏览 1 评论 0 原文

假设我有一个 class Tstd::list

std::list<T> l;

将其传递给函数时,我会使用一个引用:

someFunction( std::list<T> &l )

什么是最好的传递方式( unique_ptrstd::list 的元素)?

std::list< std::unique_ptr<T> >  l;

像这样:

someFunction( std::unique_ptr<T> ptr )

或者这样:

someFunction( T* ptr )

或者这样:

someFunction( T &ref )

例如,我如何使用 std::listback() 函数来调用它?恕我直言,这些都是“某种”等价的,但我确信我在这里遗漏了一些东西。

谢谢

Say I have a std::list of class T's:

std::list<T> l;

When passing it into functions, I would use a reference:

someFunction( std::list<T> &l )

What is the best way to pass around (the elements) of a std::list of unique_ptrs?

std::list< std::unique_ptr<T> >  l;

Like this:

someFunction( std::unique_ptr<T> ptr )

Or this:

someFunction( T* ptr )

Or this:

someFunction( T &ref )

And what how would I call it using the std::list's back() function for example? These are IMHO all "kind of" equivalent, but I'm sure I'm missing something here.

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦幻的味道 2024-09-16 03:47:40

从最好到最差的顺序:

  1. someFunction(const T&);
  2. someFunction(T&);
  3. someFunction(const std::unique_ptr&);
  4. someFunction(std::unique_ptr&);

第一个是最好的,因为它不会修改对象,并且无论您如何分配它,它都会与该对象一起工作(例如,您可以毫无问题地切换到shared_ptr)。

无论您使用什么智能指针,第二个都将起作用;但是,它假设您可以修改该对象,并且只要您可以将某些内容设置为 const,您就应该这样做。

数字 3 和 4 都允许所指向的对象发生变异;然而,#3 不允许修改智能指针,而#4 则允许。两者都有一个缺点,即它们强制使用 unique_ptr,而上面的两个无论智能指针类如何都可以工作。

像在其他一些示例中那样按值传递 unique_ptr 不是一个选项; unique_ptr 应该是唯一的。如果要复制它,请考虑使用shared_ptr。

对于前两个,如果您在 back() 的结果上调用它,它将如下所示:

someFunction(*(lst.back()));  // dereference lst.back() before passing it in.

对于后两个,如果您在 back() 的结果上调用它,它将如下所示:

someFunction(lst.back()); // pass the smart pointer, not the object to
                          // which the smart pointer currently points.

In order of best to worse:

  1. someFunction(const T&);
  2. someFunction(T&);
  3. someFunction(const std::unique_ptr<T>&);
  4. someFunction(std::unique_ptr<T>&);

The first one is the best because it does not modify the object it and it will work with the object no matter how you have allocated it (for example, you could switch to shared_ptr with no problems).

Number two will also work regardless of what smart pointer you are using; however, it assumes that you can modify the object, and whenever you can make something const, you should.

Numbers 3 and 4 both allow the object being pointed-to to be mutated; however, #3 does not allow the smart pointer to be modified, while number 4 does. Both have the disadvantage that they force the use of unique_ptr, whereas the two above it would work regardless of smart pointer class.

Passing a unique_ptr by value, as you have in some of the other examples is not an option; a unique_ptr is supposed to be unique. If you are copying it, consider using shared_ptr.

For the first two, if you invoked it on the result of back(), it would look like:

someFunction(*(lst.back()));  // dereference lst.back() before passing it in.

For the latter two, if you invoked it on the resut of back(), it would look like:

someFunction(lst.back()); // pass the smart pointer, not the object to
                          // which the smart pointer currently points.
难理解 2024-09-16 03:47:40

不要不要按值传递unique_ptr,首先,如果没有std::move,它就无法编译,如果你这样做< /strong> 使用 std::move 它将清空您存储在 list 中的值,并且您将无法再访问它。

这是因为 unique_ptr 不可复制,它没有 unique_ptr::unique_ptr(const unique_ptr& other) 类型的复制构造函数,而是只有移动构造函数 (unique_ptr::unique_ptr(unique_ptr&& source))。

Do not pass unique_ptr by value, first of all it won't compile without a std::move and if you do use std::move it will empty the value you have stored in your list and you won't be able to access it any more.

This is because unique_ptr is not copyable, it doesn't have a copy constructor of type unique_ptr::unique_ptr(const unique_ptr<T>& other) instead it only has a move constructor (unique_ptr::unique_ptr(unique_ptr<T>&& source)).

oО清风挽发oО 2024-09-16 03:47:40

unique_ptr 以及包含 unique_ptr 的类/实例可以在 std::list (和其他容器)中使用,前提是它们具有移动构造函数 class_name(class_name &&)已定义(unique_ptr 当然也有)。

当您传递这些元素时,您总是在移动(而不是复制)它们,因此您总是在左值上使用 std::move() ,就像

my_list.push_back(std::move(my_element));
这表明您正在将元素传递(=移动)到列表中,并且在该操作之后 my_element 为“空”(如空 unique_ptr)。

例子:

typedef std::unique_ptr<uint8_t[]> data_ptr;

class data_holder
{
private:
    int something_about_data;
    data_ptr data;
public:
    data_holder(data_ptr && _data)
        : data(std::move(_data))
    {}

    // hey compiler, please generate a default move constructor for me
    // despite of present destructor
    data_holder(data_holder &&) = default;

    ~data_holder()
    {
        // ...
    }

    bool is_empty() const { return ! bool(data); }
}

// ...
{
    // ...
    data_holder the_element(data_ptr(new uint8_t[DATA_SIZE]));

    // move the_element into the_list
    the_list.push_back(std::move(the_element));
    if (the_element.is_empty())
        std::cerr << "data_holder 'the_element' is now empty!" << std::endl;
    // ...
}

unique_ptr and also classes / instances containing unique_ptr can be used in std::list (and other containers), provided that they have move constructor class_name(class_name &&) defined (which unique_ptr, of course, has).

When you pass around those elements, you're always moving (and not copying) them, so you always use std::move() on lvalues, like in

my_list.push_back(std::move(my_element));
this makes visible that you're passing (= moving) the element into the list, and that my_element is "empty" (like empty unique_ptr) after that operation.

Example:

typedef std::unique_ptr<uint8_t[]> data_ptr;

class data_holder
{
private:
    int something_about_data;
    data_ptr data;
public:
    data_holder(data_ptr && _data)
        : data(std::move(_data))
    {}

    // hey compiler, please generate a default move constructor for me
    // despite of present destructor
    data_holder(data_holder &&) = default;

    ~data_holder()
    {
        // ...
    }

    bool is_empty() const { return ! bool(data); }
}

// ...
{
    // ...
    data_holder the_element(data_ptr(new uint8_t[DATA_SIZE]));

    // move the_element into the_list
    the_list.push_back(std::move(the_element));
    if (the_element.is_empty())
        std::cerr << "data_holder 'the_element' is now empty!" << std::endl;
    // ...
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文