字符串引用参数的效率C++

Efficiency of string reference parameters in C++

本文关键字:效率 C++ 参数 引用 字符串      更新时间:2023-10-16

C++当参数是字符串时,通过使它们引用字符串对象,就像当参数是程序员创建的类的对象一样时,是否有任何明显的速度/效率?例如,如果我有一个名为 Person 的类,它有名字和姓氏,我可以为其中一个构造函数做:

Person(const string& firstName, const string& lastName);

与。

Person(string firstName, string lastName);

是第一个更有效率,还是获得的效率微不足道以至于无关紧要?

是第一个更有效率的,

它可能是,潜在的。但不一定。

还是获得的效率微不足道,无关紧要?

这取决于很多事情。如果字符串很短(足以适应目标系统的小字符串优化(,那么无论哪种方式,差异都可能很小。

如果您不打算存储字符串的副本,并且字符串很大,则引用可能会明显更快。

如果要存储副本,并将右值传递给函数,并且字符串很大,则非引用可能会明显更快,因为您可以通过移动来创建副本。


无论如何,这些替代方案之间的差异在您的程序中是否显着,只能通过测量来找到。

而不是这两种方法

Person(const string& firstName, const string& lastName);

Person(string firstName, string lastName);

更有效的方法是将以下两个构造函数放在一起时

Person(const string &firstName, const string &lastName);
Person( string &&firstName, string &&lastName );

这种方法

Person(const string& firstName, const string& lastName);

当参数为右值时效率较低。

这种方法

Person(string firstName, string lastName);

当参数为左值时效率较低。

以下是两个演示程序,显示了三种方法之间的差异。

#include <iostream>
struct A
{
static int value;
explicit A() : x( ++value )
{
std::cout << "explicit A(), x = " << x << "n";
}
A( const A &a ) noexcept : x( ++value )
{
std::cout << "A( const A & ), x = " << x << "n";
}
A( A &&a ) noexcept : x( ++value )
{
std::cout << "A( A && ), x = " << x << "n";
}
~A()
{
std::cout << "~A(), x = " << x << "n";
}
int x;
};
int A::value = 0;
struct B
{
B( const A &a1, const A &a2 ) : a1( a1 ), a2( a2 )
{
std::cout << "B( const A &, const A & )n";
}
A a1, a2;
};
struct C
{
C( A a1, A a2 ) : a1( std::move( a1 ) ), a2( std::move( a2 ) )
{
std::cout << "C( A, A )n";
}
A a1, a2;
};
struct D
{
D( const A &a1, const A &a2 ) : a1( a1 ), a2( a2 )
{
std::cout << "D( const A &, const A & )n";
}
D( A &&a1, A &&a2 ) : a1( std::move( a1 ) ), a2( std::move( a2 ) )
{
std::cout << "D( A &&, A && )n";
}
A a1, a2;
};
int main()
{
A a1;
A a2;
std::cout << 'n';
B b( a1, a2 );
std::cout << "b.a1.x = " << b.a1.x << ", b.a2.x = " << b.a2.x << 'n';
std::cout << 'n';
C c( a1, a2 );
std::cout << "c.a1.x = " << c.a1.x << ", c.a2.x = " << c.a2.x << 'n';
std::cout << 'n';
D d( a1, a2 );
std::cout << "d.a1.x = " << d.a1.x << ", d.a2.x = " << d.a2.x << 'n';
std::cout << 'n';
return 0;
}

程序输出为

explicit A(), x = 1
explicit A(), x = 2
A( const A & ), x = 3
A( const A & ), x = 4
B( const A &, const A & )
b.a1.x = 3, b.a2.x = 4
A( const A & ), x = 5
A( const A & ), x = 6
A( A && ), x = 7
A( A && ), x = 8
C( A, A )
~A(), x = 6
~A(), x = 5
c.a1.x = 7, c.a2.x = 8
A( const A & ), x = 9
A( const A & ), x = 10
D( const A &, const A & )
d.a1.x = 9, d.a2.x = 10
~A(), x = 10
~A(), x = 9
~A(), x = 8
~A(), x = 7
~A(), x = 4
~A(), x = 3
~A(), x = 2
~A(), x = 1

#include <iostream>
struct A
{
static int value;
explicit A() : x( ++value )
{
std::cout << "explicit A(), x = " << x << "n";
}
A( const A &a ) noexcept : x( ++value )
{
std::cout << "A( const A & ), x = " << x << "n";
}
A( A &&a ) noexcept : x( ++value )
{
std::cout << "A( A && ), x = " << x << "n";
}
~A()
{
std::cout << "~A(), x = " << x << "n";
}
int x;
};
int A::value = 0;
struct B
{
B( const A &a1, const A &a2 ) : a1( a1 ), a2( a2 )
{
std::cout << "B( const A &, const A & )n";
}
A a1, a2;
};
struct C
{
C( A a1, A a2 ) : a1( std::move( a1 ) ), a2( std::move( a2 ) )
{
std::cout << "C( A, A )n";
}
A a1, a2;
};
struct D
{
D( const A &a1, const A &a2 ) : a1( a1 ), a2( a2 )
{
std::cout << "D( const A &, const A & )n";
}
D( A &&a1, A &&a2 ) : a1( std::move( a1 ) ), a2( std::move( a2 ) )
{
std::cout << "D( A &&, A && )n";
}
A a1, a2;
};
int main()
{
B b( A{}, A{} );
std::cout << "b.a1.x = " << b.a1.x << ", b.a2.x = " << b.a2.x << 'n';
std::cout << 'n';
C c( A{}, A{} );
std::cout << "c.a1.x = " << c.a1.x << ", c.a2.x = " << c.a2.x << 'n';
std::cout << 'n';
D d( A{}, A{} );
std::cout << "d.a1.x = " << d.a1.x << ", d.a2.x = " << d.a2.x << 'n';
std::cout << 'n';
return 0;
}

程序输出为

explicit A(), x = 1
explicit A(), x = 2
A( const A & ), x = 3
A( const A & ), x = 4
B( const A &, const A & )
~A(), x = 2
~A(), x = 1
b.a1.x = 3, b.a2.x = 4
explicit A(), x = 5
explicit A(), x = 6
A( A && ), x = 7
A( A && ), x = 8
C( A, A )
~A(), x = 6
~A(), x = 5
c.a1.x = 7, c.a2.x = 8
explicit A(), x = 9
explicit A(), x = 10
A( A && ), x = 11
A( A && ), x = 12
D( A &&, A && )
~A(), x = 10
~A(), x = 9
d.a1.x = 11, d.a2.x = 12
~A(), x = 12
~A(), x = 11
~A(), x = 8
~A(), x = 7
~A(), x = 4
~A(), x = 3

可以看出,在这两个程序中,与类BC相比,类D的行为更有效。

嗯, 你让我想起了我的一位教授曾经教过我的一条好的经验法则。

当您必须决定是否将对象传递给函数时 按值或按引用:如果对象大于对它的引用,最多 4 倍- 我们将传递对象本身, 如果它大于 4x- 那么我们将传递对它的引用。

当然,这是基于这样的假设,即无论哪种方式,我们都不打算更改对象。