这种在 C++ 中创建局部变量的方法是合法的

It is legal this approach for create a local variable in C++

我是 C++ 的新手,尝试了解如何在 C++ 中创建和使用 class。 为此,我有以下代码:

class MyClass
{ 
    public:
    MyClass()
    {
        _num = 0;
        _name = "";
    }

    MyClass(MyClass* pMyClass)
    {
        _num = pMyClass->_num;
        _name = pMyClass->_name;
    }

    void PrintValues() { std::cout << _name << ":" << _num << std::endl; }
    void SetValues(int number, std::string name)
    {
        _num = number;
        _name = name;
    }

    private:
    int _num;
    std::string _name;
};


int main()
{
    std::vector<MyClass*> myClassArray;
    MyClass myLocalObject = new MyClass();

    for (int i = 0; i < 3; i++)
    {
        myLocalObject.SetValues(i, "test");
        myClassArray.push_back(new MyClass(myLocalObject));
    }

    myClassArray[1]->PrintValues();
    // use myClassArray further   
}

从网上找了一个类似的例子,试着理解一下。 我的意图是用新的 class 对象填充 myClassArray。 如果我使用 VisualStudio 2022 编译上面的代码,我不会出错,但我不确定它不会产生内存泄漏,或者是否有更快更简单的方法。

尤其是下面这行我不明白: MyClass myLocalObject = new MyClass();

myLocalObject是在栈上创建的,但是是用堆值初始化的(因为是new的)。如果使用 new 运算符, delete 必须应用在哪里?

感谢您的任何建议!

您在 MyClass myLocalObject = new MyClass(); 处发生内存泄漏,因为 dynamically-allocated 对象用于 converting-construct 新的 myLocalObject (这几乎是但不完全是复制构造函数) 然后指针丢失。

你也没有展示使用vector的代码,但是如果它不删除里面的指针,你会有更多的内存泄漏。

没有理由 almost-copy-constructor;编译器为您提供了更好的真实 copy-constructor.

更快更简单的方法是认识到这段代码根本不需要指针。

class MyClass
{ 
    public:
    MyClass()
        : _num(), _name()   // initialize is better than assignment
    {
        //_num = 0;
        //_name = "";
    }

    // compiler provides a copy constructor taking const MyClass&
    //MyClass(MyClass* pMyClass)
    //{
    //    _num = pMyClass->_num;
    //    _name = pMyClass->_name;
    //}

    void PrintValues() { std::cout << _name << ":" << _num << std::endl; }
    void SetValues(int number, std::string name)
    {
        _num = number;
        _name = name;
    }

private:
    int _num;
    std::string _name;
};


int main()
{
    std::vector<MyClass> myClassArray;  // not a pointer
    MyClass myLocalObject; // = new MyClass();   // why copy a default instance when you can just default initialize?

    for (int i = 0; i < 3; i++)
    {
        myLocalObject.SetValues(i, "test");  // works just as before
        myClassArray.push_back(/*new MyClass*/(myLocalObject)); // don't need a pointer, vector knows how to copy objects
        // also, this was using the "real" copy-constructor, not the conversion from pointer
    }

    myClassArray[1].PrintValues(); // instead of ->
    // use myClassArray further   
}

对于需要指针的情况,例如多态性,使用智能指针:

std::vector<std::unique_ptr<MyClass>> myClassArray;  // smart pointer
myClassArray.push_back(make_unique<MyDerivedClass>(stuff));

std::unique_ptr 会在对象从 vector 中移除时自动释放对象(除非您明确将其移出),避免需要记住 delete.

类.

对象的实例化基本上有2种方式

动态分配(在堆上)

MyClass* myLocalObject = new MyClass(); // dynamically allocates memory and assigns memory address to myLocalObject

循环示例:

class MyClass
{
private:
    int _num;
    std::string _name;

public:
    // let's add an additional constuctor having default values
    // that makes it easier later on
    // if parameters are passed, they are used, or the defalt values, if not
    // can call it like MyClass(), MyClass(123), or MyClass(456,"hello")
    // you might want to pass larger data as reference, to avoid copying it
    MyClass(int num=0, std::string name = "some default text")
        : _num(num), _name(name)
    {}
};

std::vector<MyClass*> myClassArray;  // your array of pointers
for (int i = 0; i < 3; i++)
    myClassArray.push_back(new MyClass(i, "test"));

// delete
for (auto& pointerToElement : myClassArray) // get a reference to each element (which is a pointer)
    delete pointerToElement; // delete element (call's destructor if defined)

在这种情况下,您必须 delete myLocalObject; 否则会发生内存泄漏。

与其处理原始指针,尤其是当刚接触 C++ 时,我建议使用智能指针,它可以为您处理内存管理。

自动分配(尽可能在堆栈上)

MyClass myLocalObject = MyClass(); // automatically allocates memory and creates myLocalObject 这通常发生在堆栈上(如果可能)。这要快得多,而且您不必处理动态内存管理

循环示例:

std::vector<MyClass> myClassArray; // now "containg" the memory of objects itself
for (int i = 0; i < 3; i++)
    {
        myClassArray.emplace_back(i, "test"); // we use emplace_back instead to construct instances of type MyClass directly into the array
    }

// no deletion required here
// destructors of each element will be called (if defined) when myClassArray is deleted automatically when out of scope

还有其他方法,比如动态堆栈分配和其他黑魔法,但建议关注“标准”。

在处理大量数据的情况下,您可能需要使用 std::vector::reserve。结合 automatic/stack 分配,通过将内存分配限制为 1 个而不是每个元素 1 个,有助于加快速度。

希望对您有所帮助:-)