【问题标题】:How can I dereference a pointer created with New without copying?如何在不复制的情况下取消引用使用 New 创建的指针?
【发布时间】:2016-02-18 08:39:55
【问题描述】:

在下面的代码 sn-p 中,我通过 new 运算符创建一个对象并将其分配给一个指针。我想做的是将它指向的对象添加到向量。似乎正在发生的事情是我很好地创建了对象,然后当我取消引用它时,这会创建对原始对象的引用。因此,当我将此 Object 的引用分配给向量时,它会创建一个副本,而我想要实际的对象。任何帮助将不胜感激。

std::vector<Object> OBJVec;

Object *O = new Object();
/*Edits some of the internals*/
addToVec(*O); //Here is the beginning of the problem: this passes a reference to the content of O.

void addToVec(Object OParam){ //Here Creates a copy of O instead of passing the actual content.
    OBJVec.push_back(OParam); // Pushes a copy of content instead of content.
}

*注意:上面的代码是我试图完成的代码的一个非常简化的版本。

关于此接口的代码的注释,此代码与 OpenGL 交互,因此 OBJVec 必须包含对象。

我已经解决这个问题很长时间了,任何帮助都会很棒。

【问题讨论】:

  • 我不确定我是否遵循。你是说你想要一个参考向量吗?在不复制的情况下获取现有对象并将其移动到向量中是没有意义的——要么移动,要么不移动。
  • 不要为此使用指针。看看emplace_back
  • 我想这个问题无法回答,除非您解释为什么在将对象推入向量之前将它们分配到向量之外。

标签: c++ pointers dereference


【解决方案1】:

行为是对的

这是std::vector::push_back的签名

void push_back( const T& value );
void push_back( T&& value );

当您取消引用指针时,您现在拥有对原始对象的引用。当您将左值引用传递给 push_back 时,将选择第一个重载。

在你的第二种情况下,它也是一个左值,所以第一个重载仍然被选中......你不能在push_back 上躲避复制,除非你传递一个rvalue 或明确的std::move

如果你想要指针,那么让你的容器成为指针的容器。 如果你想引用,那么让你的容器是 reference_wrapper 到你的对象

但是,如果你执行这些路线,你还有额外的内存管理工作要做

【讨论】:

  • 感谢您的澄清,这是我明确告知我其工作原理所需的确切信息。非常清晰简洁。
【解决方案2】:

由于std::vector 处理它自己的内存分配(默认情况下)1,你不能在它之外分配一个元素然后让向量指向它,除非你让向量的 value_type一个指针本身,即std::vector&lt;Object*&gt;,并将指针本身传递给addToVec

std::vector<Object*> OBJVec; // Make a vector of pointers instead of objects
Object *O = new Object();

addToVec(O); // Do not dereference here

void addToVec(Object *OParam) { // Use a pointer here as the argument
    OBJVec.push_back(OParam);
}

但是,一旦将元素从向量中删除并且不再使用它们,您就需要释放它们。为了简化这一点,您可以改用unique_ptrs 的向量,它们是智能指针,一旦不再需要它就会为您解除分配对象。

如果您需要指针向量,则不能应用此解决方法。那么你不能对向量之外的每个对象使用new。这必然会导致对象被分开分配,而不是确保连续的内存布局,这是任何采用数组的 OpenGL 函数所要求的。您需要使用 new Object[count] 来分配一个数组,或者干脆完全放弃手动内存的想法,只使用一个对象向量而不分配它之外的元素。


1) 你可以改变这种行为,但仍然不可能像现在这样在向量之外单独分配每个元素。

【讨论】:

    【解决方案3】:

    我认为这应该更好(这样你就不会复制任何东西):

    std::vector<Object*> OBJVec;
    Object *O = new Object();
    
    addToVec(O); 
    
    void addToVec(Object* OParam){
        OBJVec.push_back(OParam);
    }
    

    【讨论】:

    • 如果你看下面的代码 sn-p,我提到 OBJVec 必须包含对象,因为它与 OpenGL 接口,因此这个答案不合适。
    【解决方案4】:

    在 C++98 中没有 moving 的概念,因此您将不得不使用指针向量,并在其中 copy 引用您的原始对象。在 C++11 中,您确实具有移动语义,因此您可以使用 std::move 从字面上移动对象。但是,我不确定这对您来说是否是个好主意。

    如今,首先使用裸new 不被认为是一种好习惯。您应该使用一些智能指针或您自己的 RAII 包装器。在你的情况下,我只需使用std::unique_pointer(C++11 - 或boost::unique_pointer),然后只需使用std::vector&lt;std::unique_pointer&lt;your_type&gt;&gt;,我可以安全地移动指针(你不能复制std::unique_pointer)。这种方法没有真正的开销,因此如果您需要堆分配和唯一所有权,这可能是要走的路。

    如果您不需要堆分配并且您使用的是 c++11,那么您一开始就不需要使用指针。只需创建您的对象并在需要时将其移动到矢量内 - 但是请确保您不再使用原始对象!

    【讨论】:

      猜你喜欢
      • 2010-10-30
      • 1970-01-01
      • 1970-01-01
      • 2015-11-28
      • 2021-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多