std::vector 不保留在实现中实例化的推回对象
std::vector not retaining pushed back objects instantiated in the implementation
我在 plane.h:
中声明了一个向量和一个对象
extern Plane Default;
extern std::vector<Plane *>universe;
它们在 plane.cpp:
中定义
Plane Default("Default");
std::vector<Plane *>universe;
平面构造函数:
Plane::Plane(const std::string &label) {
/* check universe to ensure uniqueness */
std::cout << this << std:endl; //DEBUG CHECK to see what I push_back
universe.push_back(this); //ACTION to keep track of the planes
std::cout << universe.back() << std::endl; //DEBUG CHECK to ensure that it was stored correctly
}
输出确认平面确实存储在向量中。
主线:
if(universe.empty()) cout << "EMPTY UNIVERSE" << endl;
说明vector没有保留值。我希望默认值(如 plane.cpp 中所定义)存储在 Universe 中。
但是,当我从 main
实例化平面时,universe 保留了这些值
我想这与本地副本、范围和按值传递有关,但我想不出一种方法来在实现内部实例化默认平面,以便它的地址保留在向量中。
我也试过从堆中声明向量,如下所示:
extern std::vector<Plane *> *universe;
并这样定义:
std::vector<Plane *> *universe = new std::vector<Plane *>;
只是程序崩溃了。
我在 Code:Blocks 16.01 和 -std=C++11
的 64 位 Vista 机器上使用 MinGW32 4.9
你的全局初始化顺序失败了:
Plane Default("Default");
std::vector<Plane *>universe;
Default
对universe
有依赖,但是构造Default
时,universe
还没有构造
这就是为什么您通常应该避免全局。
您的情况的解决方法是更改顺序,假设有相同的翻译单元:
std::vector<Plane *>universe;
Plane Default("Default");
如果您对指针的范围有疑问,也许使用 shared_ptr 就足够了?我不知道你的整体设计,但是,如果你担心指针的持久性可能会被删除或移动但仍然需要数据;智能指针可能就是答案。如果任何地方都存在循环问题,请使用 weak_ptr 来解决它。
祝你好运!
应该可以解决您遇到的问题。我将提供一些指南来防止出现此类问题。
一般来说,最好避免使用 extern
声明变量访问的全局数据。最好使用函数接口提供对全局数据的访问。
你可以改变
extern std::vector<Plane *>universe;
至
extern std::vector<Plane *>& getUniverse();
并将其实现为:
extern std::vector<Plane *>& getUniverse()
{
static std::vector<Plane *>universe;
return universe;
}
有了它,您可以将 Plane
的构造函数更改为:
Plane::Plane(const std::string &label) {
getUniverse().push_back(this);
}
这将消除与全局数据初始化顺序相关的问题。
你也可以改变
extern Plane Default;
至
extern Plane& getDefaultPlane();
并将其实现为
extern Plane& getDefaultPlane()
{
static Plane Default("Default");
return Default;
}
如果必须在初始化时构造默认值 Plane
,您可以使用类似以下内容的内容:
// Use a helper struct in an anonymous namespace to initialize
// whatever needs to be initialized.
namespace
{
struct Initializer
{
Initializer();
};
}
// Make sure that Initializer::Initializer() gets called
// at initialization time.
static Initializer initer;
Initializer::Initializer()
{
// Trigger construction of the default Plane
getDefaultPlane();
}
我在 plane.h:
中声明了一个向量和一个对象extern Plane Default;
extern std::vector<Plane *>universe;
它们在 plane.cpp:
中定义Plane Default("Default");
std::vector<Plane *>universe;
平面构造函数:
Plane::Plane(const std::string &label) {
/* check universe to ensure uniqueness */
std::cout << this << std:endl; //DEBUG CHECK to see what I push_back
universe.push_back(this); //ACTION to keep track of the planes
std::cout << universe.back() << std::endl; //DEBUG CHECK to ensure that it was stored correctly
}
输出确认平面确实存储在向量中。
主线:
if(universe.empty()) cout << "EMPTY UNIVERSE" << endl;
说明vector没有保留值。我希望默认值(如 plane.cpp 中所定义)存储在 Universe 中。
但是,当我从 main
实例化平面时,universe 保留了这些值我想这与本地副本、范围和按值传递有关,但我想不出一种方法来在实现内部实例化默认平面,以便它的地址保留在向量中。
我也试过从堆中声明向量,如下所示:
extern std::vector<Plane *> *universe;
并这样定义:
std::vector<Plane *> *universe = new std::vector<Plane *>;
只是程序崩溃了。 我在 Code:Blocks 16.01 和 -std=C++11
的 64 位 Vista 机器上使用 MinGW32 4.9你的全局初始化顺序失败了:
Plane Default("Default");
std::vector<Plane *>universe;
Default
对universe
有依赖,但是构造Default
时,universe
还没有构造
这就是为什么您通常应该避免全局。
您的情况的解决方法是更改顺序,假设有相同的翻译单元:
std::vector<Plane *>universe;
Plane Default("Default");
如果您对指针的范围有疑问,也许使用 shared_ptr 就足够了?我不知道你的整体设计,但是,如果你担心指针的持久性可能会被删除或移动但仍然需要数据;智能指针可能就是答案。如果任何地方都存在循环问题,请使用 weak_ptr 来解决它。
祝你好运!
一般来说,最好避免使用 extern
声明变量访问的全局数据。最好使用函数接口提供对全局数据的访问。
你可以改变
extern std::vector<Plane *>universe;
至
extern std::vector<Plane *>& getUniverse();
并将其实现为:
extern std::vector<Plane *>& getUniverse()
{
static std::vector<Plane *>universe;
return universe;
}
有了它,您可以将 Plane
的构造函数更改为:
Plane::Plane(const std::string &label) {
getUniverse().push_back(this);
}
这将消除与全局数据初始化顺序相关的问题。
你也可以改变
extern Plane Default;
至
extern Plane& getDefaultPlane();
并将其实现为
extern Plane& getDefaultPlane()
{
static Plane Default("Default");
return Default;
}
如果必须在初始化时构造默认值 Plane
,您可以使用类似以下内容的内容:
// Use a helper struct in an anonymous namespace to initialize
// whatever needs to be initialized.
namespace
{
struct Initializer
{
Initializer();
};
}
// Make sure that Initializer::Initializer() gets called
// at initialization time.
static Initializer initer;
Initializer::Initializer()
{
// Trigger construction of the default Plane
getDefaultPlane();
}