3

I have a c++ class Foo with an stl std::string as member. Further I have a STL std::vector<Foo> vecFoo containing objects of class Foo by value (not pointers to objects of Foo). Now I was advised by a friend not to implement it in this way but to build the vector with pointers: std::vector<Foo*> or use boost smart pointers. He discussed that a vector, which involves lots of copy operations on its members (allocating more space when adding members etc.) will make problems when the contained classes have dynamic members like std::string. Might there occur any problems?

For my understanding the std::string actually does a deep copy (or copy on write) when class Foo might be copied by the std::vector, as Foo calls copy constructors for all of its members. My friend argued that it is a problem if the string members are of different length among all Foo objects in the vector when the vector is allocating new space. What do you think?

The only reason for using pointers to Foo inside the vector is speed. A pointer to Foo (Foo*) is copied much faster than the complete class Foo, isnt it? Thx for discussion!

4

3 回答 3

2

我想,std::vector如果你要为每个元素对象分配new. 但是,如果您的元素对象足够大(不是因为字符串长度,而是因为它的“非指针”成员)带有指针的向量可以执行得更好或不可以- 这取决于向量重新分配频率。

考虑很少以对数std::vector方式分配空间的事实,因为它分配的空间总是比之前分配的空间多两倍。

使用 C++11 情况会更好,其中std::vector将使用移动语义来避免复制字符串的字符。但是,如果您的编译器不生成默认的移动构造函数,您可能需要在您的类中实现移动构造函数才能使这个东西起作用。

甚至在 C++11 之前,一些std::string实现就使用了写时复制策略,因此只需对字符串进行“深度复制”就不需要复制底层字符数组,除非其中一个副本被修改。

如果向量中的所有 Foo 对象中的字符串成员的长度不同,则会出现问题

这肯定不是问题——std::string对象当然在内部拥有一个指向字符数组的指针,而不是数组本身。

我敢肯定,在做出此类级别的优化决策之前,您应该使用分析器分析您的程序。

于 2013-10-31T10:51:40.410 回答
2

这里有一个权衡。您的 Foo 是否足够复杂以至于复制它比复制指针或智能指针要昂贵得多?您是否希望向量在执行期间经常调整大小,从而导致复制?或者,与使用指针(并且必须在之后清理)或智能指针的额外复杂性相比,复制 Foo 的向量的成本是否可以接受?在向量中存储指针有其自身的成本,因为指向的对象在内存中不一定是连续的。(虽然按值存储时 Foos 中包含的字符串将数据分散在内存中。)

尝试简单的实现(Foo的向量),测量它的性能,然后才考虑切换到(智能)指针的优化。

于 2013-10-31T10:49:28.230 回答
0

你有两个选择:

  1. 使用 std::unique_ptr 或 std::shared_ptr
  2. 按值使用它并提供移动语义

如果你使用第二个选项你必须以这种方式定义 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" ) );
于 2013-10-31T11:02:20.337 回答