C++ string或const char*,哪一个用作构造函数参数更有效

C++ string或const char*,哪一个用作构造函数参数更有效,c++,C++,我发现sizeof(string)对于VC和GCC分别是28B和32B(不包括堆上分配的数据部分)。这使我非常怀疑使用字符串作为C++构造函数的参数的效率。所以我做了一个小实验如下: class Foo { static int inc; int val; int id; public: Foo(int value) :val(value), id(Foo::inc++) { std::cout << to_string() <&

我发现
sizeof(string)
对于VC和GCC分别是28B和32B(不包括堆上分配的数据部分)。这使我非常怀疑使用字符串作为C++构造函数的参数的效率。所以我做了一个小实验如下:

class Foo
{
    static int inc;
    int val;
    int id;
public:
    Foo(int value) :val(value), id(Foo::inc++) {
        std::cout << to_string() << " being constructed\n";
    }
    ~Foo() {
        std::cout << to_string() << " being destroyed\n";
    };
    Foo(Foo const &other) :Foo(other.val) {
        std::cout << other.to_string() << " being copied\n";
    }
    Foo& operator=(Foo const &other) {
        val = other.val;
        std::cout << other.to_string() << " being copied\n";
    }
    Foo(Foo &&other) :Foo(other.val) {
        std::cout << other.to_string() << " being moved\n";
    }
    Foo& operator=(Foo &&other) {
        val = other.val;
        std::cout << other.to_string() << " being moved\n";
    }
    int value() const noexcept { return val; }
    std::string to_string() const {
        return std::string("Foo_") + std::to_string(id) + "_(" + std::to_string(val) + ")";
    }

};
int Foo::inc = 0;


struct Bar {
    Bar(Foo const &foo) :val(foo) {}
    Bar(Foo &&foo) :val(std::move(foo)) {}
private:
    Foo val;
};

//------- run it ------
Bar bar {42};
显然,临时的Foo实例是在ctor的参数处创建的。因此,我假设当我将一个
const char*
传递给一个需要字符串的构造函数时,同样的过程也会发生,也就是说,一个temp str>=28/32字节会在移动/复制后立即被创建和删除。这样的花费让我很不舒服。别误会,我将使用
字符串
作为类的数据成员,我只担心ctor的形式参数类型


无论如何,如果我将
string
参数替换为
const char*
,考虑到我总是可以求助于
string::c_str()?我想听听你的看法。如果我的分析有什么问题,请指出。如果有某种机制可以消除临时字符串的成本,请教我如何工作。如果临时字符串不可避免,我是否必须同时使用
const char*
string&
来重载ctor,一个用于避免临时字符串,另一个用于右值字符串以避免深度复制?提前谢谢

请注意,您的问题明确提到了构造函数参数,因此此答案引用了这些参数

其他推理适用于赋值运算符和设置器。(有关更多详细信息,请参阅)


如果要将字符串作为数据成员存储在对象中,则不可避免地必须创建字符串

因此,最简单的选择是创建字符串作为构造函数参数的副作用,然后将其移动到数据成员中

在以下示例中,不会创建并销毁临时字符串。所有分配的资源都存储在
数据中
(通过使用move)

根据
sizeof
分析,请注意此大小与动态(堆)存储无关
std::string
有时会分配用于存储字符数据

这只是内部数据成员的大小,这些成员在堆栈上分配(自动存储持续时间),这非常快


堆栈分配通常不应该引起您的任何关注。

请注意,您的问题明确提到了构造函数参数,因此此答案引用了这些参数

其他推理适用于赋值运算符和设置器。(有关更多详细信息,请参阅)


如果要将字符串作为数据成员存储在对象中,则不可避免地必须创建字符串

因此,最简单的选择是创建字符串作为构造函数参数的副作用,然后将其移动到数据成员中

在以下示例中,不会创建并销毁临时字符串。所有分配的资源都存储在
数据中
(通过使用move)

根据
sizeof
分析,请注意此大小与动态(堆)存储无关
std::string
有时会分配用于存储字符数据

这只是内部数据成员的大小,这些成员在堆栈上分配(自动存储持续时间),这非常快


堆栈分配通常不应该引起您的任何关注。

std::string并不是最便宜的内存类,因为它优化了小对象。这使得使用它确实有问题,尽管它也有很好的API函数和很多安全性/可用性

你应该担心吗? 如果代码不是性能关键的,不要担心!在程序的生命周期中获得几微秒是不值得的

相反,在您的代码上运行一个探查器,并修复您可以找到的瓶颈

通过值/构造引用传递std::string 假设您使用的是优化编译器并传递标志O2,O3。。。在许多情况下,编译器可以消除开销。如果需要,在标头中实现For。如果通过值传递,请不要忘记
std::move

正在传递std::string\u视图 在标准库的较新标准中,string_视图可用,如果不可用,您可以轻松地从GSL复制它。。。 此类类似于原始字符指针(+size),可用于需要std::string传递字符串的位置


最后,如果您想存储字符串,您仍然需要转换为std::.string

std::string并不是最便宜的内存类,因为小型对象优化。这使得使用它确实有问题,尽管它也有很好的API函数和很多安全性/可用性

你应该担心吗? 如果代码不是性能关键的,不要担心!在程序的生命周期中获得几微秒是不值得的

相反,在您的代码上运行一个探查器,并修复您可以找到的瓶颈

通过值/构造引用传递std::string 假设您使用的是优化编译器并传递标志O2,O3。。。在许多情况下,编译器可以消除开销。如果需要,在标头中实现For。如果通过值传递,请不要忘记
std::move

正在传递std::string\u视图 在标准库的较新标准中,string_视图可用,如果不可用,您可以轻松地从GSL复制它。。。 此类类似于原始字符指针(+size),可用于需要std::string传递字符串的位置

最后,如果你
Foo_0_(42) being constructed
Foo_1_(42) being constructed
Foo_0_(42) being moved
Foo_0_(42) being destroyed
Foo_1_(42) being destroyed
class Foo
{
public:    
    Foo(std::string data)
        : data_(std::move(data))
    {}
private:
    std::string data_;
};

int main()
{
    const char* foo = "...";
    Foo a(foo);

    std::string bar = "...";
    Foo b(std::move(bar));

    Foo c("...");
}