我有一个带有stl std::string
成员的c ++类Foo。此外,我有一个STL std::vector<Foo> vecFoo
按值包含类Foo的对象(不是Foo
对象的指针)。现在我被朋友告知不要以这种方式实现它,而是用指针构建向量:std::vector<Foo*>
或使用boost智能指针。他讨论了一个向量,它涉及对其成员进行大量复制操作(在添加成员时分配更多空间等),当包含的类具有动态成员(如std::string
)时会产生问题。可能会出现任何问题吗?
据我所知,std::string
实际上可以在std::vector
复制类Foo时执行深层复制(或写入时复制),因为Foo会为其所有成员调用复制构造函数。我的朋友认为,当向量分配新空间时,如果字符串成员在向量中的所有Foo对象中的长度不同,则会出现问题。你觉得怎么样?
在向量中使用指针Foo
的唯一原因是速度。指向Foo(Foo*
)的指针比完整的类Foo
复制得快得多,不是吗?
Thx供讨论!
答案 0 :(得分:2)
这里有一个权衡。您的Foo是否足够复杂,复制它比复制指针或智能指针要昂贵得多?您是否期望在执行期间频繁调整矢量大小,从而导致副本?或者,复制Foo向量的成本是否可以接受使用指针(以及之后必须清理)或智能指针的额外复杂性?在向量中存储指针有其自己的成本,因为指向的对象在内存中不一定是连续的。 (按值存储时,Foos中包含的字符串会将数据分散在内存中。)
尝试简单的实现(Foo的矢量),测量其性能,然后才考虑切换到(智能)指针的优化。
答案 1 :(得分:2)
我猜,如果要用std::vector
分配每个元素对象,带有指针的new
根本不会更有效。但是如果你的元素对象足够大(不是因为字符串长度,而是因为它的'非指针'成员)带指针的向量可以执行更好的或不是 - 它取决于向量重新分配频率。
考虑std::vector
很少分配空间 logarithmical 的事实,因为它总是分配比前一次分配的空间多两倍的空间。
使用C ++ 11,情况会更好,std::vector
将使用move semantics来避免确保复制字符串的字符。但是如果你的编译器没有生成default move constructor,你可能需要在你的类中实现移动构造函数才能使这个东西工作。
即使在C ++ 11之前,一些std::string
实现使用了写时复制策略,因此只需对字符串进行“深层复制”就不需要复制基础字符数组,除非其中一个副本被修改。
如果字符串成员的长度不同,则会出现问题 向量中的所有Foo对象
这肯定不是问题 - std::string
对象当然在内部持有指向字符数组的指针,而不是数组本身。
我确定,您应该使用分析器分析您的程序,然后才能在此级别做出优化决策。
答案 2 :(得分:0)
您有两种选择:
如果您使用第二个选择您必须以这种方式定义Foo
struct Foo
{
// default ctor
Foo( const std::string& s = "" ) : name( s ) {}
// copy ctor
Foo( const Foo& rhs ) : name( rhs.name ) {}
// move ctor
Foo( Foo&& rhs ) : name( std::move( rhs.name ) ) {}
// assign operator
Foo& operator = ( const Foo& f )
{
name = f.name;
return *this;
}
// move operator
Foo& operator = ( Foo&& f )
{
std::swap( name, f.name );
return *this;
}
string name;
};
FooVec v;
// construct in place
v.emplace_back( "foo1" );
v.emplace_back( "foo2" );
// or move
v.push_back( std::move( Foo( "foo3" ) );