从头开始设计新系统.我将使用STL来存储某些长寿命对象的列表和地图.
问题:我是否应该确保我的对象具有复制构造函数并在我的STL容器中存储对象的副本,或者通常更好地自己管理生命和范围并将指针存储到我的STL容器中的那些对象?
我意识到这在细节方面有点短暂,但我正在寻找"理论上"更好的答案,如果它存在,因为我知道这两种解决方案都是可能的.
使用指针的两个非常明显的缺点:1)我必须在超出STL的范围内管理这些对象的分配/释放.2)我无法在堆栈上创建临时对象并将其添加到我的容器中.
还有什么我想念的吗?
经过对valgrind的大量调查后,我得出结论,std :: vector制作了你想要push_back的对象的副本.
这是真的吗?没有副本,向量不能保留对象的引用或指针?
谢谢
我是Windows平台上的C++程序员.我正在使用Visual Studio 2008.
我通常在内存泄漏的代码中结束.
通常我通过检查代码发现内存泄漏,但它很麻烦,并不总是一个好方法.
由于我买不起付费内存泄漏检测工具,我希望你们建议尽可能避免内存泄漏的方法.
在boost库中是否有一些与C++ 1x的std :: unique_ptr等效的类?我正在寻找的行为是能够拥有异常安全的工厂功能,就像这样......
std::unique_ptr<Base> create_base()
{
return std::unique_ptr<Base>(new Derived);
}
void some_other_function()
{
std::unique_ptr<Base> b = create_base();
// Do some stuff with b that may or may not throw an exception...
// Now b is destructed automagically.
}
Run Code Online (Sandbox Code Playgroud)
编辑:现在,我正在使用这个黑客,这似乎是我能在这一点上得到的最好的......
Base* create_base()
{
return new Derived;
}
void some_other_function()
{
boost::scoped_ptr<Base> b = create_base();
// Do some stuff with b that may or may not throw an exception...
// Now b is deleted automagically.
}
Run Code Online (Sandbox Code Playgroud) 我更喜欢在任何地方使用引用,但是当你使用STL容器时,你必须使用指针,除非你真的想按值传递复杂的类型.我觉得很难转换回参考,这似乎是错误的.
是吗?
澄清...
MyType *pObj = ...
MyType &obj = *pObj;
Run Code Online (Sandbox Code Playgroud)
这不是'脏',因为你可以(即使只是在理论上,因为你先检查它)取消引用一个NULL指针?
编辑:哦,你不知道对象是否是动态创建的.
std::list<Node *> lst;
//....
Node * node = /* get from somewhere pointer on my node */;
lst.remove(node);
Run Code Online (Sandbox Code Playgroud)
std :: list :: remove方法是否调用每个被删除元素的析构函数(和空闲内存)?如果是,我怎么能避免呢?
析构函数可能不会抛出异常(因此在异常处理期间可以完成堆栈展开),并且必须释放分配给该对象的任何资源(因此不会泄漏资源).包含多个其他对象(或分配了多个资源)的对象的设计可能会在STL容器中记录指向它们的指针.因此析构函数将使用以下与迭代器相关的方法:
begin(),end()对于容器operator++ 对于有效的迭代器operator*或者operator->对于有效的迭代器但是为了保证析构函数不会抛出异常并释放其资源,您需要依赖那些永远不会抛出异常的方法.
依赖那些从不抛出异常的方法是否安全?很难想象一个实际的实现会抛出异常,因为STL迭代器本质上是一个指针.但标准C++是否要求这些方法永远不会抛出异常?我没有在C++标准中找到明确的陈述.
编辑:有趣的情况是C++ 03,当你想拥有一个指向资源的容器.这样做有充分的理由; 例如,如果您有多态资源.正如BjörnPollex在他的回答中指出的那样,如果你使用一个资源容器(比如a std::list< Resource >)而不是一个指向资源的指针的容器,容器的析构函数将为你处理对象的破坏(释放)Resource.
请考虑以下代码:
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
struct A
{
int a;
A(int a_):a(a_) {}
};
int main()
{
vector<auto_ptr<A> > as;
for (int i = 0; i < 10; i++)
{
auto_ptr<A> a(new A(i));
as.push_back(a);
}
for (vector<auto_ptr<A> >::iterator it = as.begin(); it != as.end(); ++it)
cout << (*it)->a << endl;
}
Run Code Online (Sandbox Code Playgroud)
在尝试编译它时,我从g ++中得到以下模糊的编译器错误:
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/proba.d" -MT"src/proba.d" -o"src/proba.o" "../src/proba.cpp"
/usr/include/c++/4.1.2/ext/new_allocator.h: In member function ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Tp*, const _Tp&) [with _Tp …Run Code Online (Sandbox Code Playgroud) 每当我需要将动态分配的对象添加到向量中时,我一直在做以下方式:
class Foo { ... };
vector<Foo*> v;
v.push_back(new Foo);
// do stuff with Foo in v
// delete all Foo in v
Run Code Online (Sandbox Code Playgroud)
它只是工作,许多其他人似乎做同样的事情.
今天,我学会了vector :: push_back可以抛出异常.这意味着上面的代码不是异常安全的.:-(所以我提出了一个解决方案:
class Foo { ... };
vector<Foo*> v;
auto_ptr<Foo> p(new Foo);
v.push_back(p.get());
p.release();
// do stuff with Foo in v
// delete all Foo in v
Run Code Online (Sandbox Code Playgroud)
但问题是新的方式冗长乏味,我看到没有人这样做.(至少不在我身边......)
我应该采用新的方式吗?
或者,我可以坚持旧的方式吗?
或者,有更好的方法吗?
有人可以解释为什么我在这里收到编译错误 - 错误C2558:类'std :: auto_ptr <_Ty>':没有可用的复制构造函数或者复制构造函数被声明为'explicit'
#include <memory>
#include <vector>
#include <string>
template<typename T>
struct test
{
typedef std::auto_ptr<T> dataptr;
typedef std::auto_ptr< test<T> > testptr;
test( const T& data ):
data_( new T(data) )
{
};
void add_other( const T& other )
{
others_.push_back( testptr( new test(other) ) );
}
private:
dataptr data_;
std::vector< testptr > others_;
};
int main(int argc, char* argv[])
{
test<std::string> g("d");
//this is the line that causes the error.
g.add_other("d");
return 0;
}
Run Code Online (Sandbox Code Playgroud)