首页 文章

指针的深拷贝传染媒介

提问于
浏览
4

我是一个非常新的程序员和一个超级初学者,所以我不太了解c . 我特别提出了关于制作指针的深层副本的问题 . 我所拥有的是一个充满POD的A类和指向这个类的指针(A * P) . 我有一个第二类B,它包含一些其他POD和一个指向A类的指针向量 . 我想填充A * P的深拷贝向量,因为在循环中我将动态分配和解除分配它 . 以下不起作用 . 我相信它是我的复制构造函数和=运算符的重载 . 这是我为了娱乐和学习而做的事情 .

class A
{
   public:  
   .....
   .....
   .....
};

class B
{
   public:  
   B();
  ~B();
   B(const B &Copier);
   B& B::operator=(const B &Overloading);
   vector<A*> My_Container;
   A* Points_a_lot;
   int counter;
 };
B::B()
{
  counter=0;
  Points_a_lot=NULL;
}
B::~B()
{
   for(size_t i=0; i<My_Container.size(); i++)
   {
      delete My_Container[i];
    }
 }
 B::B(const B &Overloading)
 {
     My_Container[counter]=new A(*Overloading.Points_a_lot);
 }
 B& B::operator=(const B &Overloading)
 {
     if(!Overloading.My_Container.empty()) 
     {
         Overloading.My_Container[counter]=new B(*Overloading.Points_a_lot);
      }
      return *this; 
  } 
 int main()
 {  A* p=NULL;
    B Alphabet;
    for(....)
    {
        p=new A;
        //some stuff example p->Member_of_A=3; etc..
        Alphabet.My_Container[Alphabet.counter]=p;
        Alphabet.counter++;
       delete p;
     }
    return 0;
   }

任何帮助都会很棒 . 我感谢你的时间 . 假设包含所需的库 .

5 回答

  • 3

    好吧,在我看来,你对操作员应该做什么非常困惑 . 在operator overloading上查看此页面 . 这应该让你开始沿着正确的路径前进 .

    其次,与你的问题无关,请查看this question,了解为什么你的字段(成员变量,你有什么)应该是私有的 .

  • 0

    你可能想看看 boost::ptr_vector . 它的界面非常类似于 std::vector ,但它是针对指针而定制的,因此:

    • 拥有资源(所以没有内存泄漏)

    • 允许多态存储(派生类)

    • 是const-correct和copy-correct

    为了使副本起作用,您必须提供 A* new_clone(A const*) 实现 .

  • 1

    看起来你应该让你的My_Container由unique_ptrs组成,这样当你分配时,vector会接管A实例的所有权

    for(....)
    {
        p=new A;
        //some stuff example p->Member_of_A=3; etc..
        Alphabet.My_Container[Alphabet.counter]=p;
        Alphabet.counter++;
       delete p;
     }
    

    所以改为将My_Container声明为

    vector<std::unique_ptr<A*> > My_Container;
    

    然后代码将是

    for(....)
    {
        p=new A;
        //some stuff example p->Member_of_A=3; etc..
        Alphabet.My_Container[Alphabet.counter]=p;
        Alphabet.counter++;
     }
    

    然后,如果您需要在A中创建一个名为clone()或其他东西的成员并将 unique_ptr 返回给该实例,请在需要创建副本时使用该成员 .

  • 0

    您的代码中存在许多错误 . 主要的一点是你的赋值运算符和复制构造函数根本没有将 vector 指针深深地复制到 A ,而是试图将 B* 放在向量的位置 . 你的赋值操作符应该做的是删除向量指向的元素,并在检查自我赋值后用源对象的向量指向的元素的深拷贝填充它 . 您的复制构造函数应填充源对象元素的深层副本 .

    其次,您应该提供一个方法,将元素添加到类的向量中,并让它在内部设置计数器变量 . 必须在外部协调向量和计数器是容易出错的,并且OOP的一个优点是避免这种错误 . 但更好的是,完全删除 counter 变量 . 你不需要它 . 你将 main 简化为:

    int main()
    {
      B Alphabet;
      for(....)
      {
        A* p = new A;
        //some stuff example p->Member_of_A=3; etc..
        Alphabet.appendElement(p); // B takes ownership, no need to delete in main
      }
    }
    

    appendElement 可能是

    class B
    {
     public:
      void appendElement(A* element) { myContainer_.push_back(element); }
      // other public methods
     private:
       std::vector<A*> myContainer_;
    };
    

    您可以通过存储某种单一所有权智能指针而不是原始指针来进一步改善所有这些 . 这意味着您不必担心自己删除 . 但这可能超出了这个问题的范围 .

    现在,你应该考虑完全避免指针 . 在这种情况下,您必须不提供复制构造函数,赋值运算符或析构函数 . 编译器合成的会很好 . 你的B级减少到

    class B
    {
     public:
      void appendElement(const A& element) { myContainer_.push_back(element); }
      // other public methods
     private:
       std::vector<A> myContainer_;
    };
    
  • 2

    我不完全明白你的要求是什么,所以我试图修复代码并做一个 B 的深层副本,因为这就是你所要求的 .

    #include <vector>
    using namespace std;
    
    class A
    {
    public:
        A() : m_someInt(0), m_someFloat(0.0f) {}
    
        // Redundant but putting it here for you to see when it is called (put break-point)
        A(const A& a_other)
        {
            m_someInt = a_other.m_someInt;
            m_someFloat = a_other.m_someFloat;
        }
    
        int   m_someInt;
        float m_someFloat;
    };
    
    class B
    {
    public:  
        B();
        ~B();
        B(const B &Copier);
        B& B::operator=(const B &Overloading);
        void Cleanup();
        void AddA(const A* a);
    
    private:
    
        vector<A*> My_Container;
        A* Points_a_lot;
    };
    
    B::B()
    {
        Points_a_lot=NULL;
    }
    
    B::~B()
    {
        Cleanup();
    }
    
    B::B(const B &Overloading)
    {
        // Deep copy B
        operator=(Overloading);
    }
    
    B& B::operator=(const B &Overloading)
    {
        // Delete old A's
        Cleanup();
    
        // Not using iterators to keep it simple for a beginner
        for (size_t i = 0; i < Overloading.My_Container.size(); ++i)
        {
            // We need new A's which will then copy from the A's in Overloading's container
            A* newA = new A( *(Overloading.My_Container[i]) );
            // Done with allocation and copy, push_back to our container
            My_Container.push_back(newA);
        }
    
        return *this; 
    }
    
    void B::Cleanup()
    {
        // Assuming B is not responsible for cleaning up Points_a_lot
        Points_a_lot = NULL;
    
        for (size_t i = 0; i < My_Container.size(); ++i)
        {
            delete My_Container[i];
        }
    
        // Automatically called when My_Container is destroyed, but here we 
        // are open to the possibiliy of Cleanup() being called by the client
        My_Container.clear(); 
    }
    
    void B::AddA(const A* a)
    {
        // We are adding a new A. In your code, the incoming A is going to 
        // be destroyed, therefore, we need to allocate a new A and copy 
        // the incoming A
        A* newA = new A(*a);
        My_Container.push_back(newA);
    }
    
    int main()
    {  
        A* p=NULL;
        B Alphabet;
        for(int i = 0; i < 10; ++i)
        {
            p = new A();
            //some stuff example p->Member_of_A=3; etc..
            Alphabet.AddA(p);
            delete p;
        }
    
        // If you put a breakpoint here and step through your code, you will see
        // `B` deep-copied
        B NewAlphabet = Alphabet;
    
        return 0;
    }
    

    几点说明:

    在循环中

    • New ing和 delete ing A 是一个坏主意 . 我知道你这样做只是为了学习,这很棒,但你可能想要牢记这一点 . 不要通过 p 销毁 A ,而是允许 B 取得新 A 的所有权

    • 使用调试器逐步查看代码,了解其工作原理

    • 在询问"why doesn't this work/compile"时尝试发布尽可能接近原始代码的代码

相关问题