C++ std::map 中对值的要求?
Requirement for value in the C++ std::map?
我声明了一个简单的结构以及默认构造函数、复制构造函数、赋值运算符和析构函数。但是,该结构不适用于 std::map.
的值类型
代码如下:
#include <string.h>
#include <iostream>
#include <string>
#include <map>
class Foo;
std::ostream & operator<<(std::ostream & os, const Foo & v);
typedef unsigned char BYTE;
struct Foo {
char type_; // char to label type
size_t num_; // number of elem, useful if array
size_t total_; // total memory
BYTE * data_; // content of memory
Foo(const char * t) : type_('c'), num_(strlen(t)+1), total_(strlen(t)+1), data_(NULL) {
data_ = new BYTE[total_];
memcpy(data_, t, total_-1);
((char *)data_)[total_-1] = '[=11=]';
}
Foo() : type_(), num_(), total_(), data_(NULL) {}
Foo(const Foo& rhs) : type_(rhs.type_), num_(rhs.num_), total_(rhs.total_), data_(NULL) {
if (total_) {
data_ = new BYTE[total_];
memcpy((char *)data_, (const char *)&rhs.data_, total_);
}
}
Foo & operator=(const Foo& rhs) {
if (&rhs != this) {
releaseData();
type_ = rhs.type_;
num_ = rhs.num_;
total_ = rhs.total_;
data_ = new BYTE[total_];
memcpy(data_, &rhs.data_, total_);
}
return *this;
}
~Foo() {
releaseData();
}
private:
void releaseData() {
delete [] data_; data_ = NULL;
}
};
inline std::ostream & operator<<(std::ostream & os, const Foo & v) {
os << "(type: " << v.type_ << ", num: " << v.num_ << ", total: " << v.total_ << ", data: " << (const char *)v.data_ << ", data addr: " << (void *)v.data_ << ")";
return os;
}
int main() {
Foo c("/home/data/");
std::map<std::string, Foo> store;
store["abc"] = Foo("/home/data/");
std::cout << c << std::endl;
std::cout << store["abc"] << std::endl;
}
代码在 Linux 上使用 gcc 4.9.2 编译。第一个打印正确打印出字符串,但第二个没有。
这段代码有什么问题?
您在复制构造函数和赋值运算符中对 memcpy()
的调用都是错误的。在这两种情况下,您都将 &rhs.data_
指定为来源:
memcpy((char *)data_, (const char *)&rhs.data_, total_);
...
memcpy(data_, &rhs.data_, total_);
通过以这种方式使用“&”,您正在复制内存中紧跟在 data_
成员之后的随机字节,不是 data_
指着。
由于 data_
已经是指向正在复制的数据的指针,您需要删除 &
并按原样使用 rhs.data_
(并且不需要类型转换):
memcpy(data_, rhs.data_, total_);
或者,摆脱所有这些手动逻辑,只使用 std::string
或 std::vector
,让编译器和 STL 为您处理所有内存管理和数据复制:
struct Foo {
char type_; // char to label type
std::string data_; // content of memory
Foo(const char * t) : type_('c'), data_(t) {}
Foo() : type_() {}
};
inline std::ostream & operator<<(std::ostream & os, const Foo & v) {
os << "(type: " << v.type_ << ", num: " << v.data_.length() << ", total: " << v.data_.capacity() << ", data: " << v.data_.c_str() << ", data addr: " << (void *)v.data_.data() << ")";
return os;
}
struct Foo {
char type_; // char to label type
std::vector<BYTE> data_; // content of memory
Foo(const char * t) : type_('c') { std::copy(t, t+(strlen(t)+1), std::back_inserter(data_)); }
Foo() : type_() {}
};
inline std::ostream & operator<<(std::ostream & os, const Foo & v) {
os << "(type: " << v.type_ << ", num: " << v.data_.size() << ", total: " << v.data_.capacity() << ", data: " << (const char*) &v.data_[0] << ", data addr: " << (void *)&v.data_[0] << ")";
return os;
}
我声明了一个简单的结构以及默认构造函数、复制构造函数、赋值运算符和析构函数。但是,该结构不适用于 std::map.
的值类型代码如下:
#include <string.h>
#include <iostream>
#include <string>
#include <map>
class Foo;
std::ostream & operator<<(std::ostream & os, const Foo & v);
typedef unsigned char BYTE;
struct Foo {
char type_; // char to label type
size_t num_; // number of elem, useful if array
size_t total_; // total memory
BYTE * data_; // content of memory
Foo(const char * t) : type_('c'), num_(strlen(t)+1), total_(strlen(t)+1), data_(NULL) {
data_ = new BYTE[total_];
memcpy(data_, t, total_-1);
((char *)data_)[total_-1] = '[=11=]';
}
Foo() : type_(), num_(), total_(), data_(NULL) {}
Foo(const Foo& rhs) : type_(rhs.type_), num_(rhs.num_), total_(rhs.total_), data_(NULL) {
if (total_) {
data_ = new BYTE[total_];
memcpy((char *)data_, (const char *)&rhs.data_, total_);
}
}
Foo & operator=(const Foo& rhs) {
if (&rhs != this) {
releaseData();
type_ = rhs.type_;
num_ = rhs.num_;
total_ = rhs.total_;
data_ = new BYTE[total_];
memcpy(data_, &rhs.data_, total_);
}
return *this;
}
~Foo() {
releaseData();
}
private:
void releaseData() {
delete [] data_; data_ = NULL;
}
};
inline std::ostream & operator<<(std::ostream & os, const Foo & v) {
os << "(type: " << v.type_ << ", num: " << v.num_ << ", total: " << v.total_ << ", data: " << (const char *)v.data_ << ", data addr: " << (void *)v.data_ << ")";
return os;
}
int main() {
Foo c("/home/data/");
std::map<std::string, Foo> store;
store["abc"] = Foo("/home/data/");
std::cout << c << std::endl;
std::cout << store["abc"] << std::endl;
}
代码在 Linux 上使用 gcc 4.9.2 编译。第一个打印正确打印出字符串,但第二个没有。
这段代码有什么问题?
您在复制构造函数和赋值运算符中对 memcpy()
的调用都是错误的。在这两种情况下,您都将 &rhs.data_
指定为来源:
memcpy((char *)data_, (const char *)&rhs.data_, total_);
...
memcpy(data_, &rhs.data_, total_);
通过以这种方式使用“&”,您正在复制内存中紧跟在 data_
成员之后的随机字节,不是 data_
指着。
由于 data_
已经是指向正在复制的数据的指针,您需要删除 &
并按原样使用 rhs.data_
(并且不需要类型转换):
memcpy(data_, rhs.data_, total_);
或者,摆脱所有这些手动逻辑,只使用 std::string
或 std::vector
,让编译器和 STL 为您处理所有内存管理和数据复制:
struct Foo {
char type_; // char to label type
std::string data_; // content of memory
Foo(const char * t) : type_('c'), data_(t) {}
Foo() : type_() {}
};
inline std::ostream & operator<<(std::ostream & os, const Foo & v) {
os << "(type: " << v.type_ << ", num: " << v.data_.length() << ", total: " << v.data_.capacity() << ", data: " << v.data_.c_str() << ", data addr: " << (void *)v.data_.data() << ")";
return os;
}
struct Foo {
char type_; // char to label type
std::vector<BYTE> data_; // content of memory
Foo(const char * t) : type_('c') { std::copy(t, t+(strlen(t)+1), std::back_inserter(data_)); }
Foo() : type_() {}
};
inline std::ostream & operator<<(std::ostream & os, const Foo & v) {
os << "(type: " << v.type_ << ", num: " << v.data_.size() << ", total: " << v.data_.capacity() << ", data: " << (const char*) &v.data_[0] << ", data addr: " << (void *)&v.data_[0] << ")";
return os;
}