用向量 c++ 中的指针成员初始化对象

Posted

技术标签:

【中文标题】用向量 c++ 中的指针成员初始化对象【英文标题】:Initialize Object with Pointer Members in a Vector c++ 【发布时间】:2015-03-14 17:59:53 【问题描述】:

当我使用push_back() 方法时,我希望能够在对象上调用一个重要的构造函数。相反,我所能做的就是将对象的浅拷贝传递给向量。当使用常规的 c 样式数组时,在创建数组时会自动调用构造函数,但由于向量是动态的,所以对象还不存在。

如何在没有两个指针指向同一个内存地址的情况下向向量添加一个新的空对象?我需要复制构造函数还是重载赋值运算符?

下面是一些演示我的问题的示例代码:

struct Object

    int *Pointer;

    Object()
    
        Pointer = new int;
        *Pointer = 42;
    

    ~Object()
    
        delete Pointer;
    
;


int main()

    std::vector <Object> *Array;
    Array = new std::vector <Object>;

    // Attempt 1
    Array->push_back(Object());

    // Attempt 2
    
        Object LocalInstance;
        Array->push_back(LocalInstance);
    

    // Error here because the destructor has already been called for 
    // LocalInstance and for Object()
    delete Array;

    return 0;

【问题讨论】:

这里不要使用指针。这是不必要的,并且会降低代码的效率和复杂性。 这是对实际代码的简化,是为了让问题更容易查看/调试。实际代码必须有这些指针。 即使您真的需要指针,您也应该更喜欢 STL 容器中的智能指针,例如 boost::shared_ptr 或 std::shared_ptr。 @dbank 我想你的意思是std::unique_ptr @Caleth 嗯...我不确定当我发表该评论时我的想法是什么,但是是的,我同意 unique_ptr's 将是我的智能指针的默认选择,除非有共享所有权的实际需求。 【参考方案1】:

@KonradRudolph 是正确的 - Array 没有理由在这里成为指针,它只是混淆了代码。

您的代码崩溃的原因是因为 LocationInstance 被传递给 push_back 但您的 Object 没有正确的复制构造函数,因此只复制了 Pointer 成员的浅表副本。当 LocalInstance 超出范围时,该对象会删除其Pointer,但容器中的副本具有相同的Pointer,这会导致在清理容器时删除释放的内存。

请查看Rule-of-Five(在 C++11 之前是三规则)。

就构造对象而言,当您将它们添加到容器时,您使用的是 C++11 吗?如果是这样,您可以emplace_back 并在添加容器时在容器中构造对象 - 这就是您想要做的吗?

这个简单的例子只给了我一个警告:

struct A

    A(int a) : member_m(a)
    

    int &member_m;
;
int main() 
    A a(1);

给我:

~/ClionProjects/so_reference_to_temporary $ clang++ -o test main.cpp
main.cpp:8:25: warning: binding reference member 'member_m' to stack allocated
      parameter 'a' [-Wdangling-field]
    A(int a) : member_m(a)
                        ^
main.cpp:13:10: note: reference member declared here
    int &member_m;
         ^
1 warning generated.

【讨论】:

我使用了对象数组的指针,因为没有它就不会抛出错误(至少对我来说不是)。会发生的情况是内存将被释放,但数组中对象的指针成员将指向无效的内存地址。我动态分配了数组,以便在两次调用析构函数时强制编译器生成错误。 那只是“运气”——删除释放的内存是未定义的行为。与许多内存错误一样,有时,当您幸运时,它会崩溃。有时它会默默地正常工作,直到它没有。像 valgrind 这样的工具对于检查这些问题的代码非常有帮助。 你说得对,我只需要一个复制构造函数。出于某种原因,它第一次不起作用,但现在可以了。【参考方案2】:
#include <iostream>

using namespace std;

// constructors examples 

class myClass 

    private:
        int* data;
    public:
        //constructor 
        myClass(int value)
        
            data = new int ;
            *data = value ;

         

        //copy constructor 
        myClass (const myClass& other)
            :myClass(*other.data)
        
                
        

        //move constructor 
        myClass (myClass&& other)
            :data(other.data)
        
            other.data = nullptr ;
             
        

        //destructor 
        ~myClass ()
        
            delete data ;
            
        
        //copy assignment 

        myClass& operator=(myClass other)
        
            std::swap (data, other.data);   
            return *this ;
        

;

int main ()

    myClass M1(5);
    myClass M2=M1;
    myClass M3(M2);
    M1 = M3;
    myClass M4(std::move(M1));
    return 0;

【讨论】:

那段代码如何回答 OP 的问题?请编辑和解释。 请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常更有帮助,质量更高,更有可能吸引投票。

以上是关于用向量 c++ 中的指针成员初始化对象的主要内容,如果未能解决你的问题,请参考以下文章

没有 new 关键字并使用指针的 C++ 对象初始化 [重复]

C++ 初始化作为对象指针容器的成员变量

如何在构造函数中初始化 C++ 对象成员变量?

C++入门篇之类和对象总结

C++,成员函数返回对包含指向 const 对象的指针的向量的 const 引用

C++入门篇之类和对象总结下