复制构造函数和动态内存 C++ [已关闭]

Copy constructors & Dynamic Memory C++ [closed]

提问人:ceolorenso 提问时间:1/28/2023 最后编辑:trincotceolorenso 更新时间:1/28/2023 访问量:131

问:


编辑问题以包括所需的行为、特定问题或错误以及重现问题所需的最短代码。这将有助于其他人回答这个问题。

10个月前关闭。

最近,我开始从事我的第一个OOP项目,在编写了程序之后,我正在尝试优化它以提高代码效率。我想将程序中被大量复制的部分放在堆上。

我不明白为什么在某些地方会复制对象。 举个例子:

在 main.cpp movies 对象中,创建了 故事 电影对象。调用Add_movie函数来检查我们尝试添加的电影是否已添加,如果没有,我们创建一个临时对象,将其私有成员初始化为正在传递的参数值,将其附加到 movies 对象的向量。当电影对象追加到向量时,将调用复制构造函数。为什么?我无法理解为什么它被复制的部分?是因为范围吗???

如果有一个对象在 main 中初始化,比如

Movie movie1{arguments};

而其他影片是基于 Movie1 创建的

Movie movie2{movie1}.

这对我来说是有道理的,但在我给出的例子中,它对我来说根本没有意义

我所指的函数示例

bool Movies::add_movie(std::string name, std::string rating, int watched)
{
    for (const Movie& obj : movies_list)
    {
        if (obj.get_name() == name) // search for a match
        {
            return false; // if found stop executing
        }
    }
    Movie temp{ name, rating, watched }; // creates a new object and initializes its private members to the passed arguments
# movies_list.push_back(temp); // appends the object to the vector
# ***    return true;
}

我不知道它是否有帮助,但有程序的代码

**main.cpp**

#include "Movie.h"
#include "Movies.h"

#include <iostream>
#include <string>

void add_movie(Movies& obj, std::string name, std::string rating, int watched)
{
    if (obj.add_movie(name, rating, watched))
    {
        std::cout << name << " succesfully added" << std::endl;
    }
    else
    {
        std::cout << name << " already has been added" << std::endl;
    }
}
// if the parent increment_watched function returns true, inform the user about the result of the operation
void increment_watched(Movies &obj, std::string name)
{
    if (obj.increment_watched(name)) // if Movies::increment_watched returns
    {
        std::cout << name << " watch count succesfully incremented by 1" << std::endl;
    }
    else {
        std::cout << name << " movie not found" << std::endl;
    }
}

int main()
{


    Movies list;

    add_movie(list, "Fight Club", "A", 1);
    add_movie(list, "Fight Club", "A", 1);
    add_movie(list, "Inception", "A", 1);

    increment_watched(list, "Fight Club");
    increment_watched(list, "Else Test");
    

    list.display();

    return 0;
}

movies.cpp

#include "Movie.h"
#include "Movies.h"

#include <iostream>

bool Movies::add_movie(std::string name, std::string rating, int watched)
{
    for (const Movie& obj : movies_list)
    {
        if (obj.get_name() == name) // search for a match
        {
            return false; // if found stop executing
        }
    }
    Movie temp{ name, rating, watched }; // creates a new object and initializes its private members to the passed arguments
    movies_list.push_back(temp); // appends the object to the vector
    return true;
}
void Movies::display() const
{
    if (movies_list.size() == 0) // checks the vector size
    {
        std::cout << "The list is empty" << std::endl;
    }
    else
    {
        std::cout << "\nThe list of the movies: " << std::endl;
        std::cout << "----------------------------" << std::endl;

        for (const Movie& obj : movies_list) 
        {
            obj.display_members(); // accesses the private members of the object that are stored in the vector and outputs them to the user
        }
    }
}
bool Movies::increment_watched(std::string name)
{
    for (Movie &obj : movies_list) // iterates through the movie objects until finds the match in name
    {
        if (obj.get_name() == name)
        {
            obj.increment_watched(); // increments watched by 1 
            return true;
        }
    }
    return false;
}

movie.cpp

#include <string>
#include <iostream>
#include "Movie.h"

// constructor for initializing private members of the object
Movie::Movie(std::string name, std::string rating, int watched)
{
    this->name = name;
    this->rating = rating;
    this->watched = watched;
}
// get methods
std::string Movie::get_name() const { return name; }
std::string Movie::get_rating() const { return rating; }
int Movie::get_watched() const { return watched; }

// display private members
void Movie::display_members() const
{
    std::cout << "Name: " << get_name() << std::endl;
    std::cout << "Rating: " << get_rating() << std::endl;
    std::cout << "Times watched: " << get_watched() << std::endl;
    std::cout << "\n" << std::endl;
}
// setter function
void Movie::increment_watched() {watched++;}

// DEBUGGING
Movie::Movie(const Movie &obj):name{obj.name}, rating{obj.rating}, watched{obj.watched} {std::cout << "copy constructor called for " << name << std::endl;}
Movie::~Movie() {std::cout << "destructor called for movie " << name << std::endl;}

调试程序数小时,以查看哪些部分正在被复制、何时复制、何时被销毁,以便更好地掌握。

观看了无数解释对象、复制构造函数、析构函数生命周期的视频,但这对我来说仍然没有意义!

C++ 堆内存 dynamic-memory-allocation 析构 复制构造函数

评论

2赞 wohlstad 1/28/2023
请发布一个最小的可重复示例
0赞 Aconcagua 1/28/2023
太长而无法完全阅读,但请注意,例如 你已经复制了字符串!为了避免,请改为通过 const 引用接受:!add_movie(std::string name, ...)add_movie(std::string const& name, ...)
0赞 Revolver_Ocelot 1/28/2023
movies_list.push_back(temp);为什么这个副本不行?您在向量之外有一个对象,现在您需要在向量具有相同数据的对象。由于您不能同时在两个地方拥有单个对象,因此会制作副本。您可以定义移动构造函数来移动所有内容并避免额外的分配。
0赞 Aconcagua 1/28/2023
这是对象被复制到任何不使用引用或指针的地方的本质。然后向量还有点特殊:除非指针或引用的向量,否则它会在内存中专门分配的部分按值保存其对象。现在的问题是:如果一个对象具有本地作用域(即驻留在用于堆栈的内存中),它如何进入向量的内部缓冲区,该缓冲区驻留在完全不同的内存位置(在堆上)。你不能拿起剪刀,把你的记忆切成碎片来移动,所以剩下的就是:复制......
1赞 Peter 1/28/2023
引用你的代码的两行 你在这里的评论是不正确的。 构造并追加 into 的副本。这就是指定成员函数的方式。Movie temp{ name, rating, watched }; movies_list.push_back(temp); // appends the object to the vectormovies_list.push_back(temp)tempmovies_listpush_back()std::vector

答:

2赞 guard3 1/28/2023 #1

push_back()获取一个对象并将其附加到向量的末尾。它必须制作副本,因为它必须保持原始对象完好无损,因为您以后可能需要它。如果要避免复制,则可以使用来触发移动构造函数。std::move

movies_list.push_back(std::move(temp));

但是,在您的示例中,您基本上希望在向量的末尾构造一个对象。 正是您所需要的;无需复制或移动,只需传递构造函数参数即可。emplace_back

movies_list.emplace_back(name, rating,watched);

评论

0赞 Peter 1/28/2023
与 at stackoverflow.com/questions/11572669/move-with-vectorpush-back 一起使用的相关讨论 简而言之:不一定有益std::move()std::vector::push_back()