为什么这个没有语法错误的嵌套 class 程序会产生垃圾输出,我该如何解决?

Why does this no syntax error nested class program produce garbage output, and how do I fix it?

以下代码包含作为 TODO 的问题的完整描述。 包括用于编译代码(无错误)的 cut/pasteable 命令行。 子实例包含它们自己的名字,初始化器应该复制它。 子实例还包含指向其父 this 实例的指针。 这些都不应该打印垃圾。 Child 还使用其 Parent 实例指针来打印父名称。 此名称由 Parent ctor 初始化,因此不应打印为垃圾。 我什至 运行 它通过 clang 和 -fsyntax-only,没有报告 warning/error。 我肯定错过了什么。帮助将不胜感激。

////////////////////////////////////////////////////////////////////////////////
//
// #####     ##    #####   ######  #    #   #####           ####   #####   #####
// #    #   #  #   #    #  #       ##   #     #            #    #  #    #  #    #
// #    #  #    #  #    #  #####   # #  #     #            #       #    #  #    #
// #####   ######  #####   #       #  # #     #     ###    #       #####   #####
// #       #    #  #   #   #       #   ##     #     ###    #    #  #       #
// #       #    #  #    #  ######  #    #     #     ###     ####   #       #
////////////////////////////////////////////////////////////////////////////////
// A class having access to all nested class instances and vice versa
// 0. presence by name in a set
// 1. by name          in a map
// 2. by index         in a vector
// 3. by name to index in a map
// and nested classes have access to parent and to each other through parent.
////////////////////////////////////////////////////////////////////////////////
// TODO produce the following instead of garbage output.
// Compile and expected output:
// $ g++ --std=c++17 -Wall -pedantic -o parent parent.cpp
// $ ./parent
// P:A
// P:B
// $ 
////////////////////////////////////////////////////////////////////////////////

#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <set>

using namespace std;

// Utility function for when things go wrong.
template<class... Args> void panic(Args... args) {
    cerr << "parent panic: ";
    (cerr << ... << args) << "\n";
    exit(1);
}

class Parent { public: //CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

    class Child { public: //cccccccccccccccccccccccccccccccccccccccccccccccccccc
        Child(Parent* p, const string& n) : parent(p), name(n) {} // Child ctor
        ~Child() {}                                               // Child dtor
        void operator()(){ cout<<parent->name<<':'<<name<<endl; } // Child ftor

        Parent*     parent; // Child Parent ptr
        const string& name; // Child name
    }; //ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

    Parent(const string& name) : name(name) {}                // Parent ctor
    ~Parent() {}                                              // Parent dtor
    void operator()() { for(auto child: vcci) { child(); } }  // Parent ftor

    void operator+=(const vector<string>& names) {
        for(auto name : names) {
            if (used.find(name) != used.end()) panic(name, " re-used,");
            used.insert(name);             // Fast search
            size_t vcN = vcci.size();      // Index for next name
            vcci.emplace_back(this, name); // construct child into vector
            Child* back = &(vcci[vcN]);    // Address of child to store
            mptr[name] = back;             // Store address of child
            mint[name] = vcN;              // map name to index
        }
    }

    string name;              // name of parent
    set<string> used;         // fast lookup of name for duplicates
    vector<Child> vcci;       // vector of emplaced Child instances
    map<string, Child*> mptr; // name lookup of Child pointer
    map<string, size_t> mint; // index of name

}; //CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

//eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
void experiment() {
    vector<string> AB = { "A", "B" };  // Names to use as Child names
    Parent parent("P");                // Named parent
    parent += AB;                      // Produce named Child instances
    parent();                          // Execute parent ftor
}

//mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
int main(int argc, char** argv) {
    experiment();
    return 0;
}

对于 for(auto name : names) ...name 是一个局部变量,它是向量中字符串的副本。该变量在循环的每次迭代中创建和销毁。然后你用 name 作为参数创建 Child 个实例——它们在它们的 name 成员中存储对该变量的引用。不久之后,变量被销毁,所有这些引用都变得悬空。

当程序实际尝试使用 Child::name 成员时,字符串早已不复存在,引用也早已悬空。通过在对象的生命周期结束后访问对象,任何使用它们的尝试都会表现出未定义的行为。

const string& name; // Child name

这是违规行。 它必须是一个字符串,而不是一个字符串引用。 简单的程序员错误。 感谢您的审阅并为我指明了正确的方向。