【发布时间】:2011-01-09 17:43:22
【问题描述】:
这是this question 的后续行动。假设我编写了一个接受或返回 const 字符串的 C++ 接口。我可以使用 const char* 以零结尾的字符串:
void f(const char* str); // (1)
另一种方法是使用 std::string:
void f(const string& str); // (2)
也可以编写一个重载并接受两者:
void f(const char* str); // (3)
void f(const string& str);
甚至是与提升字符串算法结合使用的模板:
template<class Range> void f(const Range& str); // (4)
我的想法是:
- (1) 不是 C++ 语言,并且在后续操作可能需要知道字符串长度时效率可能较低。
- (2) 不好,因为现在
f("long very long C string");调用了涉及堆分配的 std::string 构造。如果f使用该字符串只是将其传递给一些需要 C 字符串的低级接口(如 fopen),那么这只是浪费资源。 - (3) 导致代码重复。尽管一个
f可以调用另一个,这取决于什么是最有效的实现。但是,我们不能基于返回类型重载,例如 std::exception::what() 返回 const char*。 - (4) 不适用于单独编译,可能会导致更大的代码膨胀。
- 根据实现的需要在 (1) 和 (2) 之间进行选择,这会将实现细节泄露给接口。
问题是:首选的方式是什么?我可以遵循任何单一的指导方针吗?你有什么经验?
编辑:还有第五个选项:
void f(boost::iterator_range<const char*> str); // (5)
它具有(1)(不需要构造字符串对象)和(2)(字符串的大小显式传递给函数)的优点。
【问题讨论】:
-
在情况 (2) 中将没有堆分配。字符串将在堆栈上构造
-
@nice:对,std::string 本身是在堆栈上分配的。但是如果你的字符串足够长或者你的实现没有使用短字符串优化,那么 std::string 将在堆上分配它的存储空间。
-
我认为只有在调用 std::string 复制构造函数时才会发生堆分配
-
@nice:那你错了。欢迎您重载 new 并自己验证(不要忘记使用“looooong 字符串”)。
-
"accepts" 和 "returns" 可能应该单独考虑(单独的选项,我的意思是,不一定是单独的问题),因为如果您 returning 一个字符串,那么您有一个内存管理问题要处理。就我个人而言,我不在乎一个函数是否接受
const char*并且我有一个string来传递它,因为它在调用代码中是一个微不足道的区别。另一种方式是琐碎的代码,即使不一定是琐碎的性能。但是,如果它返回一个const char*,那么我必须担心谁释放它,而如果它返回一个string(对象,而不是引用),我不会。
标签: c++