Tôi đã viết sơ lược về một lớp để tạo cấu trúc động trong C++. Thành phần cấu trúc động được lưu trữ liên tục với (theo như các thử nghiệm của tôi cho biết) cùng một đệm mà trình biên dịch sẽ chèn vào trong cấu trúc tĩnh tương đương. Do đó, các cấu trúc động có thể được chuyển đổi hoàn toàn thành các cấu trúc tĩnh để tương thích với các API hiện có.Trên nền tảng nào sự cố này sẽ xảy ra và tôi có thể cải thiện nó như thế nào?
Quan trọng nhất, tôi không tin tưởng bản thân mình để có thể viết mã chất lượng tăng cường có thể biên dịch và hoạt động trên nhiều nền hoặc ít hơn bất kỳ nền tảng nào. Những phần nào của mã này có nguy cơ cần sửa đổi?
Tôi có một câu hỏi liên quan đến thiết kế khác: Là một cách truy cập đơn giản cung cấp trình biên dịch với thông tin kiểu tĩnh cần thiết cho mã loại an toàn? Vì vậy, người dùng của dynamic_struct
phải chỉ định loại thành viên mà họ đang truy cập, bất cứ khi nào họ truy cập. Nếu loại đó thay đổi, tất cả các số của các truy cập trở nên không hợp lệ và sẽ gây ra các sự cố ngoạn mục — trở xuống, không thành công. Và nó không thể bị bắt lúc biên dịch. Đó là một rủi ro rất lớn, và tôi muốn khắc phục.
Ví dụ về sử dụng:
struct Test {
char a, b, c;
int i;
Foo object;
};
void bar(const Test&);
int main(int argc, char** argv) {
dynamic_struct<std::string> ds(sizeof(Test));
ds.append<char>("a") = 'A';
ds.append<char>("b") = '2';
ds.append<char>("c") = 'D';
ds.append<int>("i") = 123;
ds.append<Foo>("object");
bar(ds);
}
Và mã sau:
//
// dynamic_struct.h
//
// Much omitted for brevity.
//
/**
* For any type, determines the alignment imposed by the compiler.
*/
template<class T>
class alignment_of {
private:
struct alignment {
char a;
T b;
}; // struct alignment
public:
enum { value = sizeof(alignment) - sizeof(T) };
}; // class alignment_of
/**
* A dynamically-created structure, whose fields are indexed by keys of
* some type K, which can be substituted at runtime for any structure
* with identical members and packing.
*/
template<class K>
class dynamic_struct {
public:
// Default maximum structure size.
static const int DEFAULT_SIZE = 32;
/**
* Create a structure with normal inter-element padding.
*/
dynamic_struct(int size = DEFAULT_SIZE) : max(size) {
data.reserve(max);
} // dynamic_struct()
/**
* Copy structure from another structure with the same key type.
*/
dynamic_struct(const dynamic_struct& structure) :
members(structure.members), max(structure.max) {
data.reserve(max);
for (iterator i = members.begin(); i != members.end(); ++i)
i->second.copy(&data[0] + i->second.offset,
&structure.data[0] + i->second.offset);
} // dynamic_struct()
/**
* Destroy all members of the structure.
*/
~dynamic_struct() {
for (iterator i = members.begin(); i != members.end(); ++i)
i->second.destroy(&data[0] + i->second.offset);
} // ~dynamic_struct()
/**
* Get a value from the structure by its key.
*/
template<class T>
T& get(const K& key) {
iterator i = members.find(key);
if (i == members.end()) {
std::ostringstream message;
message << "Read of nonexistent member \"" << key << "\".";
throw dynamic_struct_access_error(message.str());
} // if
return *reinterpret_cast<T*>(&data[0] + i->second.offset.offset);
} // get()
/**
* Append a member to the structure.
*/
template<class T>
T& append(const K& key, int alignment = alignment_of<T>::value) {
iterator i = members.find(key);
if (i != members.end()) {
std::ostringstream message;
message << "Add of already existing member \"" << key << "\".";
throw dynamic_struct_access_error(message.str());
} // if
const int modulus = data.size() % alignment;
const int delta = modulus == 0 ? 0 : sizeof(T) - modulus;
if (data.size() + delta + sizeof(T) > max) {
std::ostringstream message;
message << "Attempt to add " << delta + sizeof(T)
<< " bytes to struct, exceeding maximum size of "
<< max << ".";
throw dynamic_struct_size_error(message.str());
} // if
data.resize(data.size() + delta + sizeof(T));
new (static_cast<void*>(&data[0] + data.size() - sizeof(T))) T;
std::pair<iterator, bool> j = members.insert
({key, member(data.size() - sizeof(T), destroy<T>, copy<T>)});
if (j.second) {
return *reinterpret_cast<T*>(&data[0] + j.first->second.offset);
} else {
std::ostringstream message;
message << "Unable to add member \"" << key << "\".";
throw dynamic_struct_access_error(message.str());
} // if
} // append()
/**
* Implicit checked conversion operator.
*/
template<class T>
operator T&() { return as<T>(); }
/**
* Convert from structure to real structure.
*/
template<class T>
T& as() {
// This naturally fails more frequently if changed to "!=".
if (sizeof(T) < data.size()) {
std::ostringstream message;
message << "Attempt to cast dynamic struct of size "
<< data.size() << " to type of size " << sizeof(T) << ".";
throw dynamic_struct_size_error(message.str());
} // if
return *reinterpret_cast<T*>(&data[0]);
} // as()
private:
// Map from keys to member offsets.
map_type members;
// Data buffer.
std::vector<unsigned char> data;
// Maximum allowed size.
const unsigned int max;
}; // class dynamic_struct
Tôi lấy phiếu bầu để đóng vì SO không chịu trách nhiệm về pe xem xét lại mã của tôi và bất kỳ câu hỏi nào có chứa mã yêu cầu cuộn tự động nhận được một ghi chú. Ah, tốt. –
Điều gì về việc viết bài này lên như một bài viết về CodeProject? Hoặc, nếu nó không được đóng cửa ở đây (có đóng cửa sẽ là một kết quả không may IMHO) thì bạn hoặc người khác có thể đính kèm một tiền thưởng cho nó. – John
Vâng, tôi chỉ có thể phải tìm kiếm các địa điểm thay thế, mặc dù tôi đã cân nhắc việc thêm tiền thưởng, và nếu có bất kỳ lợi ích nào vẫn còn trong câu hỏi, tôi chắc chắn sẽ. –