为什么这个没有语法错误的嵌套 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
这是违规行。
它必须是一个字符串,而不是一个字符串引用。
简单的程序员错误。
感谢您的审阅并为我指明了正确的方向。
以下代码包含作为 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
这是违规行。 它必须是一个字符串,而不是一个字符串引用。 简单的程序员错误。 感谢您的审阅并为我指明了正确的方向。