3

我想编写一个跨平台的函数(win32 和 linux),并返回日期时间的字符串表示 [hh:mm:ss dd-mm-yyyy]。

知道我只想以流方式将返回的字符串用作临时字符串,如下所示:

std::cout << DateTime() << std::endl;

我考虑用以下原型编写一个函数

const char* DateTime();

如果您返回一个字符数组,则必须在完成后将其删除。但我只想要一个临时的,我不想担心取消分配字符串。

所以我写了一个只返回一个 std::string 的函数:

#include <ctime>
#include <string>
#include <sstream>

std::string DateTime()
{
    using namespace std;

    stringstream ss;
    string sValue;
    time_t t = time(0);
    struct tm * now = localtime(&t);

    ss << now->tm_hour << ":";
    ss << now->tm_min << ":";
    ss << now->tm_sec << " ";
    ss << now->tm_mday + 1 << " ";
    ss << now->tm_mon + 1 << " ";
    ss << now->tm_year + 1900;

    sValue = ss.str();

    return sValue;
}

我意识到我正在返回 DateTime 中的堆栈变量的副本。这是低效的,因为我们在 DateTime 堆栈上创建字符串,填充它,然后返回一个副本并销毁堆栈上的副本。

c++11 移动语义革命是否已经解决了这种低效率问题——我可以对此进行改进吗?

4

4 回答 4

6

lapin,您的代码是很好的 C++11 代码。在 C++98/03中,由于编译器优化,您的代码可能会很高效,但不能保证这些优化。在 C++11 中,这些相同的优化可能仍会使您的返回免费,但万一他们不这样做,您的字符串将被移动而不是复制。

因此,按价值回报无罪!:-)

小尼特:

最佳实践是在第一次使用时声明您的值,而不是在块的顶部:

string sValue = ss.str();
return sValue;

或者甚至:

return ss.str();

但这只是一个小问题。你的代码很好而且很高效。

于 2012-06-30T01:12:32.793 回答
5

另一种方法是使其成为带有流插入器的函数对象,如下所示:

struct DateTime()
{
    friend std::ostream& operator<<(std::ostream& os, DateTime)
    {
        time_t t = time(0);
        struct tm * now = localtime(&t);

        os << now->tm_hour << ":";
        os << now->tm_min << ":";
        os << now->tm_sec << " ";
        os << now->tm_mday + 1 << " ";
        os << now->tm_mon + 1 << " ";
        os << now->tm_year + 1900;

        return os;
    }

    // Could be converted to a static method,
    //  since DateTime has no internal state
    std::string str() const
    {
        // the following 3 lines can be replaced by
        //  return boost::lexical_cast<std::string>(*this);
        std::ostringstream ss;
        ss << *this;
        return ss.str();
    }

    operator std::string() const
    { return str(); }
};
于 2012-06-30T08:35:02.587 回答
-1

在没有 RVO/NRVO 的世界中,这应该避免在 C++11 之前的标准库中进行复制构造。在带有用于字符串的移动构造函数的 C++11 后库中,它仍然避免调用移动构造函数;这可能只是一个微不足道的差异,但 OP 仍然在询问如何做得更好。

(是的,我同意从字符串继承是丑陋的,但它确实有效。)

#include <ctime>
#include <string>
#include <sstream>
#include <iostream>

using namespace std;

class DateString : public string {

public:
DateString() : string()     {

    stringstream ss;
    time_t t = time(0);
    struct tm * now = localtime(&t);

    ss << now->tm_hour << ":";
    ss << now->tm_min << ":";
    ss << now->tm_sec << " ";
    ss << now->tm_mday + 1 << " ";
    ss << now->tm_mon + 1 << " ";
    ss << now->tm_year + 1900;

    append(ss.str());

}
};

int main()
{
    cout << DateString() << endl;
    return 0;
}
于 2012-06-29T23:51:48.997 回答
-1

好的,我知道这不是线程安全的,而且我可能会被否决到地狱结束,但我在我正在使用的库中看到了以下内容(CERN 的根):

const char * myfunc(){

  static std::string mystr;

  /*populate mystr */

  return mystr.c_str();
}

这只有在你知道没有人会愚蠢到抓住指针的情况下才有效。

这是一种无论如何都不会泄漏的临时方法。

于 2012-06-30T01:16:01.687 回答