C ++通用列表分配

时间:2010-04-30 11:25:29

标签: c++ generics list templates stl

我显然已经在Java领域停留了太长时间......是否有可能使用以下Java代码的C ++:

interface Foo {}

class Bar implements Foo {}

static List<Foo> getFoo() {
  return new LinkedList<Foo>();
}

static List<Bar> getBar() {
  return new LinkedList<Bar>();
}

List<? extends Foo> stuff = getBar();

Foo是Bar的子类。

所以在C ++ ....

std::list<Bar> * getBars()
{
  std::list<Bar> * bars = new std::list<Bar>;
  return bars;
}

std::list<Foo> * stuff = getBars();

希望有道理......

6 个答案:

答案 0 :(得分:4)

更改

std::list<Bar> & getBars()

std::list<Bar> getBars()

这原则上会按值返回,但是有复制构造的删除机制,所以优化编译器应该能够优化

std::list<Bar> bars (getBars());

不涉及复制构造函数,只是直接构建bars

此外,在C ++ 0x中有移动构造函数,因此即使复制/移动因任何原因未被删除,上述代码也是有效的。

编辑错过的子类问题:

一般情况下,这不可能在C ++中干净利落(我假设FooBar超类,否则你所做的事情没什么意义)。可能有一些reinterpret_cast黑魔法,但我强烈反对它。

最接近的可能就是这个(相应调整getBars()):

std::list <Bar*>  bars (getBars ());
std::list <Foo*>  foos (bars.begin (), bars.end ());

然而,这给你带来了一些非常重要的内存管理负担。使用某种自动指针可能有所帮助,但据我记得只有shared_ptr可用于容器。

最后,Foo / Bar类层次结构应该使用虚函数,否则你想要做的几乎肯定不会起作用(即除非你真的想忽略子类中的任何覆盖)

答案 1 :(得分:3)

我认为在C ++中没有意义。

首先,您返回不再存在的引用。为避免这种情况,您可以将std :: list作为参考参数传递给函数,如

void fillFoos( std::list< Foo > & foos )

其次,foos不是条形图,不能相互复制,除非我认为你提供了正确的复制操作符。

但是如果你使用继承,你所有的foos和bar应该是指针(如果你可以聪明的那些作为来自boost或tr1的shared_ptr指针)。但这并不意味着副本有效。

我不确定你想做什么,但在这种情况下从JAVA转换到C ++是行不通的。如果你创建了foos,它们将自动拥有条形图。

std::list< Foo > foos; // just work fine

如果你想要一个构造为foos的条形列表:

std::list< Bar * > bars;
bars.push_back( new Foo() );

或者正如我将它放在带有shared_ptr的实际C ++代码中一样:

typedef boost::shared_ptr< Bar >;
typedef boost::shared_ptr< Foo >;
typedef std::list< BarPtr > BarList;

BarList bars;

bars.push_back( FooPtr( new Foo() ) );

答案 2 :(得分:2)

你需要对象支持那些操作的构造函数,所以你不应该返回一个引用,而是一个将被复制的直接对象,否则返回一个指针,即:

std::list<Bar> getBars()
{
    std::list<Bar> Bars;
    return Bars;
}

std::list<Bar>* getBars()
{
    return new std::list<Bar>();
}

std :: list支持复制另一个列表的对象,但仅当该列表属于同一类型时,即:您无法隐式地从std::list<Bar>复制到std::list<Foo>,但您可以从std::list<Foo>std::list<Foo>

答案 3 :(得分:2)

要么我在这里得到完全错误,要么你的Java代码不起作用。我刚试过它不起作用。原因是,Java are not covariant中的通用容器(这意味着,如果BarFoo的子类,它也不起作用)。其次,如果FooBar的子类,那么您可以为Foo分配Bar个引用,但不能相反(在Java和C ++中都没有)。

C ++中的容器也不是协变的。但你可以做到

std::list<Foo*> FooList;
// fill FooList;
std::list<Bar*> BarList(FooList.begin(), FooList.end());

如果FooBar的子类。但是,这会导致FooList中的所有指针都被复制到BarList中。这意味着,如果您之后通过添加或删除元素更改FooList,则这些更改将不会反映在BarList中。

答案 4 :(得分:1)

除了返回对局部变量的引用外,一切都很好。它保存在堆栈中,并在函数返回后释放。

答案 5 :(得分:0)

此外,新的std :: list将返回一个指针,而不是一个引用。