这个简单的C ++函数有什么问题?

时间:2013-11-01 02:08:38

标签: c++ function

这是一个来自interiew的问题,以及下面附带的代码。这个功能出了什么问题?

string f() {
    return "hello world";
}

对我而言,没有任何错误,我甚至可以使用此功能运行程序:

#include <iostream>
#include <string>
using namespace std;

string f() {
    return "hello world";
}

int main() {
    string s2=f();
    cout<<s2<<endl;
}

此功能的 错误是什么?

3 个答案:

答案 0 :(得分:6)

嗯......有一些安慰,在这类问题中,通常没有正确的答案。你可能希望最好的方法是通过展示你的专业知识来彰显面试官的优点和缺点(a.k.a. code masturbation)。

从样式的角度来看,使用按值返回返回对象通常很糟糕。考虑:

X f();

X x;
x = f();

f分配一个X.需要返回一个X,因此在堆栈上放置一个额外的副本作为返回值。最后,堆栈上的x通过赋值运算符复制到x中。总共有3个X出现在内存中。有人可能会说这是低效的,所以当值是一个对象时,你应该尝试不按值返回。

但是,一个更精明的受访者可能会指出:

  • 一些编译器优化了临时副本。对于这种优化,我认为在这里是否通过复制构造函数或相等运算符进行X的赋值会产生影响。说“复制精灵”,看看面试官是否抬起眉毛:What is copy elision and how does it optimize the copy-and-swap idiom?。我猜副本省略可能在这里工作,因为该功能在同一个翻译单元中,因此很容易内联。
  • 几乎所有字符串类的实现都会在写入时实现copy,其中在这种情况下将保留字符串文本数据的单个副本,其余数据保存在堆栈中并且基本上不会产生任何开销字符串被复制。
  • 如果您正在使用Visual Studio的早期版本,则会出现内存泄漏

那么,有哪些替代方案?

X const& f();

可能被视为替代方案。但是,这有其自己的样式问题,因为调用者不清楚结果的生命周期。也许下次调用会使之前的参考结果无效?谁知道?

另外

void f_get( X& result );

可能是首选(由一些采访者)。这有以下好处:

  • 没有局部变量的副本
  • 没有不确定生命的参考/指针
  • 在X是字符串的情况下,只保留一个文本数据的副本(尽管所有情况都是如此)

在这两者中,牺牲了可读性 - 在一般情况下,调用者现在必须更加注意哪些参数是功能参数,哪些是用于保存结果。

在O.P.中,堆栈中字符串文字的生命周期也不是很明显。当函数返回时是否从堆栈中取消分配?可能不是 - 它的可能保存在静态存储区中(最好检查规格以确定)。但如果没有,那么结果是什么 - 可能没有,因为字符串可能在堆上创建了一个char const *的副本,除非你有一些奇怪的字符串实现谁的构造函数可以告诉区分文字与非文字参数与一些聪明的模板类型 - 特质魔术。

无论如何,喷出一些B.S.如果不合适的话,这肯定会得分。

此外,您的控制台是否输出ascii,UTF-8或unicode?对于其中一个人来说,该程序可能是错误的,而且在没有英语的地区也是错误的。

您是否检查过stdout是否具有有效值,或者您是否在Windows中没有-D_CONSOLE进行编译,或者某些嵌入式设备或游戏控制台中没有stdout,您必须重定向到日志库(或崩溃)?

嗯......接受你的选择。

临时副本可能是他们正在寻找的机器人。 因为在一个字符串的情况下暂时没有后果(也可能是复制省略),面试官闻到接骨木果子,他的母亲是山羊

答案 1 :(得分:4)

这个功能本身并没有什么不妥 - 这是完全安全的。但是,由于此函数始终返回相同的字符串,因此您可以考虑使用常量替换该函数,如下所示:

static const string kHelloWorld = "hello world";

cout << kHelloWorld << endl;

这样做的好处是,这个字符串只有一个副本,它现在是一个命名常量,这意味着它可以根据需要进行更改,并且函数调用和返回没有开销。

希望这有帮助!

答案 2 :(得分:2)

string f() {
    return "hello world";
}

根据templatetypedef的回答,这将导致在每个使用点临时构造一个字符串。

您可以通过以下方式解决此问题:

const std::string& f()
{
    static const std::string hw("Hello world");
    return hw;
}

这样,多次调用会产生对第一次调用期间创建的单个std :: string实例的引用。每次调用f()时,可能是性能成本,而它会检查是否已经创建了本地静态 - 我不确定编译器中的最新技术是什么是

相比之下,如果您有客户端代码直接使用常量...

static const std::string hw("Hello world");

...如果您想要开始返回运行时确定的值(例如,基于环境变量选择语言中的“Hello world”消息),则必须让每个客户端更新其代码。如果您坚持使用该函数,那么您可以选择返回引用的几个常量中的哪一个,或者您可以将返回类型从by-const-reference更改为by-value并返回任何动态生成的文本。