为什么我的child_dirs std::list 不保留添加到其中的对象?

Why is my child_dirs std::list not retaining the objects that are added to it?

提问人:stevoh 提问时间:8/7/2023 更新时间:8/7/2023 访问量:56

问:

我是一名长期的 C# 开发人员,试图学习 C++,我正在编写一个程序来递归处理文件夹结构以构建目录对象的层次结构。顺便说一句,我知道recursive_directory_iterator,但我不认为它会给我所需的控制水平。为什么我的child_dirs std::list 不保留添加到其中的对象?我很确定这是因为它超出了范围,但我不明白,因为顶级目录在范围内,所以它的成员也应该不是吗?我在想,一旦我在具有大量子项(例如C:)的起始路径上运行它,我可能需要切换到动态存储,但我现在正试图让事情变得更简单......或者没有办法在不切换到动态存储的情况下做我想做的事情?

目录.h

#pragma once
#include <list>
#include <filesystem>
#include <iostream>
#include "FileEntry.h"
class Directory
{
public:
    std::string debug;
    std::string path;
    std::list<FileEntry> child_files {};
    std::list<Directory> child_dirs {};

    Directory();
    Directory(std::filesystem::directory_entry in_path);
    Directory(std::string in_path);
};

目录:.cpp

#include <list>
#include <filesystem>
#include "Directory.h"

//Constructors
Directory::Directory(){
}

Directory::Directory(std::filesystem::directory_entry in_path) {
    path = in_path.path().string();
}
Directory::Directory(std::string in_path) {
    path = in_path;
}

FileEntry.h

#pragma once
#include <string>
#include <filesystem>
class FileEntry
{
public:
    std::string FileName = "";
    uintmax_t SizeInBytes = 0;

    FileEntry(std::filesystem::directory_entry entry) 
    {
        FileName = entry.path().string();
        SizeInBytes = entry.file_size();
    }
};

主 .cpp

void process_dir(Directory& path);
void print_dir(Directory& dir);

int main()
{
    Directory start_dir("C:\\Users\\steve\\source\\repos\\topdir");
    std::cout << "--- Starting Dir: " << start_dir.path << " ---" << std::endl;

    process_dir(start_dir);

    std::cout << "Done." << std::endl;
    print_dir(start_dir);
}

void process_dir(Directory& dir)
{
    std::cout << "Dir: " << dir.path << " child_dirs.size: " << dir.child_dirs.size() << std::endl;
    for (std::filesystem::directory_entry entry : std::filesystem::directory_iterator(dir.path))
    {
        if (entry.is_directory()) 
        {
            Directory new_dir(entry);
            dir.child_dirs.push_back(new_dir);
            process_dir(new_dir);
        }
        if (entry.is_regular_file() || entry.is_block_file() || entry.is_character_file()) {
            dir.child_files.push_back(entry);
            std::cout << "   File: " << entry.path() << " child_files.size: " << dir.child_files.size() << std::endl;
        }
    }
}

void print_dir(Directory& dir)
{
    std::cout << "DIR: " << dir.path << " child_files.size: " << dir.child_files.size() << std::endl;
    for (FileEntry file : dir.child_files)
    {
        std::cout << " File: " << file.FileName << std::endl;
    }
    for (Directory child_dir : dir.child_dirs)
    {
        print_dir(child_dir);
    }
}

输出:

--- Starting Dir: C:\Users\steve\source\repos\topdir ---
Dir: C:\Users\steve\source\repos\topdir child_dirs.size: 0
Dir: C:\Users\steve\source\repos\topdir\middir1 child_dirs.size: 0
Dir: C:\Users\steve\source\repos\topdir\middir1\lowdir1 child_dirs.size: 0
   File: "C:\\Users\\steve\\source\\repos\\topdir\\middir1\\lowdir1\\lowdir1filea.txt" child_files.size: 1
   File: "C:\\Users\\steve\\source\\repos\\topdir\\middir1\\lowdir1\\lowdir1fileb.txt" child_files.size: 2
Dir: C:\Users\steve\source\repos\topdir\middir1\lowdir2 child_dirs.size: 0
   File: "C:\\Users\\steve\\source\\repos\\topdir\\middir1\\lowdir2\\lowdir2filea.txt" child_files.size: 1
   File: "C:\\Users\\steve\\source\\repos\\topdir\\middir1\\lowdir2\\lowdir2fileb.txt" child_files.size: 2
   File: "C:\\Users\\steve\\source\\repos\\topdir\\middir1\\middir1filea.txt" child_files.size: 1
   File: "C:\\Users\\steve\\source\\repos\\topdir\\middir1\\middir1fileb.txt" child_files.size: 2
Dir: C:\Users\steve\source\repos\topdir\middir2 child_dirs.size: 0
   File: "C:\\Users\\steve\\source\\repos\\topdir\\middir2\\middir2filea.txt" child_files.size: 1
   File: "C:\\Users\\steve\\source\\repos\\topdir\\middir2\\middir2fileb.txt" child_files.size: 2
   File: "C:\\Users\\steve\\source\\repos\\topdir\\topdirfilea.txt" child_files.size: 1
   File: "C:\\Users\\steve\\source\\repos\\topdir\\topdirfileb.txt" child_files.size: 2
Done.
DIR: C:\Users\steve\source\repos\topdir child_files.size: 2
 File: C:\Users\steve\source\repos\topdir\topdirfilea.txt
 File: C:\Users\steve\source\repos\topdir\topdirfileb.txt
DIR: C:\Users\steve\source\repos\topdir\middir1 child_files.size: 0
DIR: C:\Users\steve\source\repos\topdir\middir2 child_files.size: 0
C++ 按引用传递 stdlist

评论

5赞 Nathan Pierson 8/7/2023
您在调用之前执行。因此,添加的副本是未处理的版本。处理发生在超出范围的局部变量上,该变量与保存到 的局部变量是分开的。dir.child_dirs.push_back(new_dir)process_dir(new_dir);new_dirdir.child_dirsdir.child_dirs
2赞 Alan Birtles 8/7/2023
与您的问题无关,但总的来说比大多数情况下要好std::vectorstd::list
0赞 stevoh 8/7/2023
@NathanPierson,交换这两个语句的顺序似乎是可行的。我认为我的 C# 体验可能会把我搞砸了。我new_dir视为一个类的实例,并假设我正在传递一个地址,包括我的列表。如果我的列表正在获得副本,我可以看到顺序在哪里很重要。这是怎么回事吗?谢谢。
1赞 Nathan Pierson 8/7/2023
new_dir 类的实例。但这并不意味着你要传递一个地址。的地址是 ,不是直接的。类传递给函数的确切方式取决于该函数的签名。在 std::list::p ush_back 的情况下,选择重载 (1),它接受对它的常量引用并将其副本添加到列表中。new_dir&new_dirnew_dirnew_dir
0赞 stevoh 8/8/2023
@NathanPierson,谢谢你澄清这个问题。伙计,我需要弄清楚这样一个事实,即对象并不总是像 C# 中那样由 ref 传递。如果您可以输入您的回复作为答案,我可以将其标记为已接受。

答: 暂无答案