避免在需要指针时创建命名变量
Avoid creating named variables when pointer is required
我一直在创建命名变量,以便能够将它们的地址传递给需要指针的构造函数,但我希望能够在构造函数或其他函数中创建它们,然后将它们的地址传递给需要指针的构造函数。
我正在使用 C++ 20,并且我有以下 类:
#include <iostream>
#include <string>
#include <vector>
#include <random>
using std::string, std::cout, std::cin, std::endl, std::vector;
class symbol {
public:
enum symbolKind {
null,
terminal,
sequence,
weighted,
random
};
protected:
symbolKind kind;
public:
virtual string evaluate() const = 0;
symbolKind getKind() {
return kind;
}
};
class nullSymbol : public symbol {
public:
nullSymbol() {
kind = symbol::null;
}
string evaluate() const override {
return "";
}
};
class terminalSymbol : public symbol {
private:
string termString;
public:
terminalSymbol(string pString) {
kind = symbol::terminal;
termString = pPhoneme;
}
string evaluate() const override {
return termString;
}
};
class sequenceSymbol : public symbol {
private:
vector<symbol*> symArray;
public:
sequenceSymbol(vector<symbol*> pArr) {
kind = symbol::sequence;
symArray = pArr;
}
string evaluate() const override {
string retStr = "";
for (symbol* current : symArray) {
retStr += current->evaluate();
}
return retStr;
}
};
class weightedSymbol : public symbol {
private:
float weight;
symbol* subSym;
public:
weightedSymbol(symbol* pSym, float pWeight) {
kind = symbol::weighted;
subSym = pSym;
weight = pWeight;
}
string evaluate() const override {
return subSym->evaluate();
}
float getWeight() {
return weight;
}
};
class randomSymbol : public symbol {
private:
vector<weightedSymbol*> symArray;
public:
randomSymbol(vector<weightedSymbol*> pArr) {
kind = symbol::random;
symArray = pArr;
}
string evaluate() const override {
float sum = 0.0;
for (weightedSymbol* current : symArray) {
sum += current->getWeight();
}
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> dis(0.0, sum);
float randomResult = dis(gen);
float prev = 0;
for (weightedSymbol* current : symArray) {
if (randomResult < (prev += current->getWeight())) return current->evaluate();
}
}
};
我一直在创建这样的符号:
terminalSymbol term_a("a");
terminalSymbol term_b("b");
sequenceSymbol seq_ab({ &term_a, &term_b});
cout << "ab test: " << seq_ab.evaluate() << endl;
但我希望能够像这样或类似的方式来做:
sequenceSymbol seq_ab_2({&terminalSymbol("a"), &terminalSymbol("b")});
cout << "ab test 2: " << seq_ab_2.evaluate() << endl;
这会在 Visual Studio 中产生错误 '&' requires l-value
。
这是一个非常简单的示例,通常会创建比这更多的变量。在这种情况下,地址被传递给 std::vector<weightedSymbol*>()
构造函数;它与 weightedSymbol()
构造函数相同,它也需要一个指针。这不仅适用于构造函数(如果有另一种方法可以实现相同的功能,它甚至不需要使用构造函数本身),但我想要一种在函数中创建堆对象然后 return 指向它们的指针在这种情况下有效。可能是我需要自己更改 类 才能正常工作,它们应该只提供相同的功能。
最后,我想根据用户输入动态创建这些符号对象。
我已经在线搜索并尝试使用多种不同的东西,但未能获得我想要的功能。实现这个的好方法是什么?大概有一个常用的technique/idiom我可以用,如果有请详细解释给我,我也可以用在其他项目中
您通过指针传递的对象需要以某种方式销毁。在此代码段中,只要您退出块,它们就会自动销毁:
terminalSymbol term_a("a");
terminalSymbol term_b("b");
sequenceSymbol seq_ab({ &term_a, &term_b});
如果创建没有命名变量的对象会怎样?您的 类 永远不会删除您通过指针传递的对象,因此调用者有责任管理每个对象的生命周期。
您的问题的一个解决方案是将对象包装到任何类型的智能指针中。例如:
class sequenceSymbol : public symbol {
public:
sequenceSymbol(vector<shared_ptr<symbol>> pArr);
};
sequenceSymbol seq_ab_2({
std::make_shared<terminalSymbol>("a"),
std::make_shared<terminalSymbol>("b")
});
我一直在创建命名变量,以便能够将它们的地址传递给需要指针的构造函数,但我希望能够在构造函数或其他函数中创建它们,然后将它们的地址传递给需要指针的构造函数。
我正在使用 C++ 20,并且我有以下 类:
#include <iostream>
#include <string>
#include <vector>
#include <random>
using std::string, std::cout, std::cin, std::endl, std::vector;
class symbol {
public:
enum symbolKind {
null,
terminal,
sequence,
weighted,
random
};
protected:
symbolKind kind;
public:
virtual string evaluate() const = 0;
symbolKind getKind() {
return kind;
}
};
class nullSymbol : public symbol {
public:
nullSymbol() {
kind = symbol::null;
}
string evaluate() const override {
return "";
}
};
class terminalSymbol : public symbol {
private:
string termString;
public:
terminalSymbol(string pString) {
kind = symbol::terminal;
termString = pPhoneme;
}
string evaluate() const override {
return termString;
}
};
class sequenceSymbol : public symbol {
private:
vector<symbol*> symArray;
public:
sequenceSymbol(vector<symbol*> pArr) {
kind = symbol::sequence;
symArray = pArr;
}
string evaluate() const override {
string retStr = "";
for (symbol* current : symArray) {
retStr += current->evaluate();
}
return retStr;
}
};
class weightedSymbol : public symbol {
private:
float weight;
symbol* subSym;
public:
weightedSymbol(symbol* pSym, float pWeight) {
kind = symbol::weighted;
subSym = pSym;
weight = pWeight;
}
string evaluate() const override {
return subSym->evaluate();
}
float getWeight() {
return weight;
}
};
class randomSymbol : public symbol {
private:
vector<weightedSymbol*> symArray;
public:
randomSymbol(vector<weightedSymbol*> pArr) {
kind = symbol::random;
symArray = pArr;
}
string evaluate() const override {
float sum = 0.0;
for (weightedSymbol* current : symArray) {
sum += current->getWeight();
}
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> dis(0.0, sum);
float randomResult = dis(gen);
float prev = 0;
for (weightedSymbol* current : symArray) {
if (randomResult < (prev += current->getWeight())) return current->evaluate();
}
}
};
我一直在创建这样的符号:
terminalSymbol term_a("a");
terminalSymbol term_b("b");
sequenceSymbol seq_ab({ &term_a, &term_b});
cout << "ab test: " << seq_ab.evaluate() << endl;
但我希望能够像这样或类似的方式来做:
sequenceSymbol seq_ab_2({&terminalSymbol("a"), &terminalSymbol("b")});
cout << "ab test 2: " << seq_ab_2.evaluate() << endl;
这会在 Visual Studio 中产生错误 '&' requires l-value
。
这是一个非常简单的示例,通常会创建比这更多的变量。在这种情况下,地址被传递给 std::vector<weightedSymbol*>()
构造函数;它与 weightedSymbol()
构造函数相同,它也需要一个指针。这不仅适用于构造函数(如果有另一种方法可以实现相同的功能,它甚至不需要使用构造函数本身),但我想要一种在函数中创建堆对象然后 return 指向它们的指针在这种情况下有效。可能是我需要自己更改 类 才能正常工作,它们应该只提供相同的功能。
最后,我想根据用户输入动态创建这些符号对象。
我已经在线搜索并尝试使用多种不同的东西,但未能获得我想要的功能。实现这个的好方法是什么?大概有一个常用的technique/idiom我可以用,如果有请详细解释给我,我也可以用在其他项目中
您通过指针传递的对象需要以某种方式销毁。在此代码段中,只要您退出块,它们就会自动销毁:
terminalSymbol term_a("a");
terminalSymbol term_b("b");
sequenceSymbol seq_ab({ &term_a, &term_b});
如果创建没有命名变量的对象会怎样?您的 类 永远不会删除您通过指针传递的对象,因此调用者有责任管理每个对象的生命周期。
您的问题的一个解决方案是将对象包装到任何类型的智能指针中。例如:
class sequenceSymbol : public symbol {
public:
sequenceSymbol(vector<shared_ptr<symbol>> pArr);
};
sequenceSymbol seq_ab_2({
std::make_shared<terminalSymbol>("a"),
std::make_shared<terminalSymbol>("b")
});