C++ how to move object to a nullptr

情到浓时终转凉″ 提交于 2020-07-22 21:39:24

问题


I am thinking a strange use case where I want to move an object to a nullptr. Maybe I should give an code fragment:

class Objpair {
   public:
      Objpair(Obj&& a, Obj&&b) : first(&a), second(&b) { }
   private:
       Obj* first;
       Obj* second;
};

The problem is that when a and b is out of scope, the first and second pointer will be dangling. If I can move Object a onto the first pointer then there should be no problem of double free and scoping issues. If the member first were declared as Obj not Obj* pointer, then the straight first(std::move(a)) would do the job. I must be doing something wrong here. I am thinking of move instead of copying because I am trying to transfer of control from another object to the current object and improve on performance.

The pointer version is used because I am thinking about polymorphic behavior for the member object.


回答1:


What you can do is move construct objects from your parameters like this:

class Objpair {
   public:
      Objpair(Obj&& a, Obj&& b)
      : first(new Obj(std::move(a)))
      , second(new Obj(std::move(b)))
      {}

   private:
       Obj* first;
       Obj* second;
};

I recommend you use std::unique_ptr:

class Objpair {
   public:
      Objpair(Obj&& a, Obj&& b)
      : first(std::make_unique<Obj>(std::move(a)))
      , second(std::make_unique<Obj>(std::move(b)))
      {}

   private:
       std::unique_ptr<Obj> first;
       std::unique_ptr<Obj> second;
};



回答2:


In a comment, you said,

first and second can point to BaseClass, Derived1, Derived2,

In that case, your best option is to provide a virtual member function in Obj to clone an object.

class Obj
{
   public:
      virtual Obj* clone() const = 0;
   ...
}

and use it to initialize first and second.

 class Objpair {
   public:
      Objpair(Obj&& a, Obj&&b) : first(a.clone()), second(b.clone()) { }
   private:
       Obj* first;
       Obj* second;
};

and make sure that you take care of deallocating memory pointed to by first and second in the destructor. See The Rule of Three for additional details.

You can use smart pointers to eliminate the need for code in your class for managing the life times of the objects. Whether you use std::unique_ptr or std::shared_ptr depends on how you wish to use Objpair.




回答3:


You can't move objects onto pointers (nullptr or otherwise). Nor can you extend the lifetime of objects by having pointers point to them - C++ simply doesn't work that way.

Since you need polymorphic behavior, you can't just copy-construct or assign an Obj pointer. You'll probably want something like a clone() method for class Obj, as discussed in this question:

Copying derived entities using only base class pointers, (without exhaustive testing!) - C++

for more on this. Remember, though - you can't extend the rvalue reference's lifetime, so you have to construct a new object somehow. Also remember to avoid memory leakage. So if your clone() produces an Obj*, you'll need to write something like:

class Objpair {
   public:
      Objpair(Obj&& a, Obj&&b) : 
         first(a.clone()), 
         second(b.clone()) 
      { }
   private:
      std::unique_ptr<Obj> first;
      std::unique_ptr<Obj> second;
};

on perhaps std::shared_ptr's instead of the unique_ptr's (see this answer about choosing between the two).

If you need "polymorphic" behavior, but you know the exact types of a and b at compile-time, and you don't mind having different ObjPair classes, you could also try something like this:

template <typename T1, typename T2>
class Objpair {
   public:
      Objpair(T1&& a, T2&&b) : first(a), second(b) 
      { }
   private:
      T1 first;
      T2 second;
};

in which case no pointers are involved (!)




回答4:


@Galik's accepted answer is good. Though it requires that Obj is at least movable, which is similar to other answers with Clone() solutions - they all put some requirements on Obj and its descendants. To remove this restriction we can change Objpair's constructor to accept std::unique_ptr<Obj>:

#include <memory>

class Obj
{
public:
    Obj() {}

    // non-copyable/non-movable
    Obj(const Obj&) = delete;
    Obj& operator=(const Obj&) = delete;
};

class Objpair {
   public:
      Objpair(std::unique_ptr<Obj>&& a, std::unique_ptr<Obj>&& b)
      : first(std::move(a))
      , second(std::move(b))
      {}

   private:
       std::unique_ptr<Obj> first;
       std::unique_ptr<Obj> second;
};

int main()
{
    Objpair p{std::make_unique<Obj>(), std::make_unique<Obj>()};
    return 0;
}

Possible bonuses are:

  • user deals with memory allocation, and so has better control over it.
  • user can use instances of a and b parameters before passing them to Objpair, polymorphically.


来源:https://stackoverflow.com/questions/55484089/c-how-to-move-object-to-a-nullptr

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!