has*_*sdf 21 c++ data-structures
我需要存储一个对象的各种属性的列表.属性由名称和数据组成,可以是任何数据类型.
我知道我可以创建一个类"Property",并使用不同的PropertySubClasses扩展它,它们只与它们存储的数据类型不同,但感觉不对.
class Property
{
Property(std::string name);
virtual ~Property();
std::string m_name;
};
class PropertyBoolean : Property
{
PropertyBoolean(std::string name, bool data);
bool m_data;
};
class PropertyFloat : Property
{
PropertyFloat(std::string name, float data);
float m_data;
};
class PropertyVector : Property
{
PropertyVector(std::string name, std::vector<float> data);
std::vector<float> m_data;
};
Run Code Online (Sandbox Code Playgroud)
现在我可以存储各种属性
std::vector<Property*>
Run Code Online (Sandbox Code Playgroud)
为了获取数据,我可以将对象强制转换为子类.或者我可以创建一个纯虚函数来处理函数内部的数据,而无需进行转换.
无论如何,创建这些不同类型的子类是不对的,这些子类仅因它们存储的数据类型而不同.有没有其他方便的方法来实现类似的行为?
我没有访问Boost.
sbi*_*sbi 28
C++ is a multi-paradigm language. It shines brightest and is most powerful where paradigms are mixed.
class Property
{
public:
Property(const std::string& name) //note: we don't lightly copy strings in C++
: m_name(name) {}
virtual ~Property() {}
private:
std::string m_name;
};
template< typename T >
class TypedProperty : public Property
{
public:
TypedProperty (const std::string& name, const T& data)
: Property(name), m_data(data);
private:
T m_data;
};
typedef std::vector< std::shared_ptr<Property> > property_list_type;
Run Code Online (Sandbox Code Playgroud)
Edit: Why using std::shared_ptr<Property> instead of Property*?
Consider this code:
void f()
{
std::vector<Property*> my_property_list;
for(unsigned int u=0; u<10; ++u)
my_property_list.push_back(new Property(u));
use_property_list(my_property_list);
for(std::vector<Property*>::iterator it=my_property_list.begin();
it!=my_property_list.end(); ++it)
delete *it;
}
Run Code Online (Sandbox Code Playgroud)
That for loop there attempts to cleanup, deleting all the properties in the vector, just before it goes out of scope and takes all the pointers with it.
Now, while this might seem fine for a novice, if you're an only mildly experienced C++ developer, that code should raise alarm bells as soon as you look at it.
The problem is that the call to use_property_list() might throw an exception. If so, the function f() will be left right away. In order to properly cleanup, the destructors for all automatic objects created in f() will be called. That is, my_property_list will be properly destroyed. std::vector's destructor will then nicely cleanup the data it holds. However, it holds pointers, and how should std::vector know whether these pointers are the last ones referencing their objects?
Since it doesn't know, it won't delete the objects, it will only destroy the pointers when it destroys its content, leaving you with objects on the heap that you don't have any pointers to anymore. This is what's called a "leak".
In order to avoid that, you would need to catch all exceptions, clean up the properties, and the rethrow the exception. But then, ten years from now, someone has to add a new feature to the 10MLoC application this has grown to, and, being in a hurry, adds code which leaves that function prematurely when some condition holds. The code is tested and it works and doesn't crash - only the server it's part of now leaks a few bytes an hour, making it crash due to being out of memory about once a week. Finding that makes for many hours of fine debugging.
Bottom line: Never manage resources manually, always wrap them in objects of a class designed to handle exactly one instance of such a resource. For dynamically allocated objects, those handles are called "smart pointer", and the most used one is shared_ptr.
Gru*_*rig 10
较低级别的方法是使用联合
class Property
union {
int int_data;
bool bool_data;
std::cstring* string_data;
};
enum { INT_PROP, BOOL_PROP, STRING_PROP } data_type;
// ... more smarts ...
};
Run Code Online (Sandbox Code Playgroud)
Dunno为什么你的其他解决方案感觉不对,所以我不知道这种方式对你来说会不会更好.
编辑:提供一些使用示例的更多代码.
Property car = collection_of_properties.head();
if (car.data_type == Property::INT_PROP) {
printf("The integer property is %d\n", car.int_data);
} // etc.
Run Code Online (Sandbox Code Playgroud)
我可能会在可能的情况下将这种逻辑放入类的方法中.您还可以使用此构造函数之类的成员来保持数据和类型字段同步:
Property::Property(bool value) {
bool_data = value;
data_type = BOOL_PROP;
}
Run Code Online (Sandbox Code Playgroud)