我不确定我是否使用了正确的术语,但问题是如何正确地构造一个将字符串作为参数的构造函数?
我习惯在构造函数中使用const char *
而不是字符串。
通常我会做这样的事情:
Name(const char* fName, const char* lName)
: firstName(0), lastName(0)
{
char * temp = new char [strlen(fName) + 1];
strcpy_s(temp, strlen(fName) + 1, fName);
firstName = temp;
char * temp2 = new char [strlen(lName) + 1];
strcpy_s(temp2, strlen(lName) + 1, lName);
lastName = temp2;
}
如果构造函数是这样的:
Name(const string fName, const string lName) { }
我还在做基本会员初始化吗?我还需要在构造函数的基础上使用字符串副本吗?
答案 0 :(得分:11)
使用std::string
和初始化列表:
std::string fName, lName;
Name(string fName, string lName):fName(std::move(fName)), lName(std::move(lName))
{
}
在这种情况下,您不需要使用非常简单的指针,您不需要分配内存,复制字符并最终解除分配。此外,由于std::string
是可移动的,因此这个新代码有机会利用移动而不是复制。阅读this也很有用。
依旧......
答案 1 :(得分:9)
我看到你已经接受了答案,但我想扩大答案。
正如deepmax所说,如果你通过值传递,你可以编写你的构造函数来利用"移动语义"。这意味着它不是复制数据,而是可以从一个变量移动到另一个变量。
这样写:
class Name{
public:
Name(std::string var): mem_var(std::move(var)){}
std::string mem_var;
};
这似乎是一个好主意,但实际上并不比复制构造函数
更有效class Name{
public:
Name(const std::string &var): mem_var(var){}
std::string mem_var;
};
这是因为在一般用例中看起来像这样:
auto main() -> int{
Name name("Sample Text");
}
任何一种方式都只能制作一份副本(见copy elision),而另一种方式
auto main() -> int{
std::string myname = "Hugh Jaynus";
Name name(myname);
}
将在'高效'中制作2份副本。按值传递移动语义方式!
这是一个很好的例子,说明复制构造函数(或通过引用传递)应该,而不是反对它的示例。
恰恰相反......
如果编写一个使用移动语义的显式构造函数,无论在什么情况下都可以得到有效的解决方案。
以下是 I 将如何写出类定义:
class Name{
public:
Name(const std::string &first_, const std::string &last_)
: first(first_), last(last_){}
Name(std::string &&first_, std::string &&last_) // rvalue reference
: first(std::move(first_)), last(std::move(last_)){}
std::string first, last;
};
然后当你使用这个类时,可以决定何时更有效。
如果我们回到我们的例子,我们可以重写它们以使用最好或最有效的构造函数:
auto main() -> int{
// pass by reference best here
Name myname("Yolo", "Swaggins");
// move most efficient here
// but never use 'first' and 'last' again or UB!
std::string first = "Hugh", last = "Jaynus";
Name yourname(std::move(first), std::move(last));
}
永远不要理所当然地认为一种解决方案比其他解决方案更好!
答案 2 :(得分:3)
我习惯这样做:
std::string fName;
std::string lName;
Name(const std::string &fName, const std::string &lName) :
fName(fName), lName(lName)
{
}
使用引用可以节省将字符串复制到堆栈上的新对象的工作,它只会将引用传递给现有字符串。一旦将它们分配给班级成员,他们就会被复制。
答案 3 :(得分:0)
如果你想保持const char *作为你的构造函数输入类型。
std::string fName;
std::string lName;
Name(const char *_fName, const char *_lName) :
fName(_fName), lName(_lName)
{
}
您可以从const char构建一个std :: string。