当我惊讶于下面的代码无法正常工作时,我正在玩模板:
#include <iostream>
#include <string>
#include <cstring>
template <class Object>
class CreatorTWO {
public:
CreatorTWO (void) {}
~CreatorTWO (void) throw () {}
template <typename... Object_Params>
Object* create (const Object_Params&... params_) {
Object _temp_obj = Object(params_...);
size_t _obj_bytes = sizeof (_temp_obj);
void * _mem_block = std::malloc (_obj_bytes);
std::memmove(_mem_block,&_temp_obj,_obj_bytes);
//The line below prints the dereferenced object before it is returned:
std::cout << *(static_cast <Object*> (_mem_block)) << '\n';
return static_cast <Object*> (_mem_block);
}
};
int main (int argc, char* argv[]) {
CreatorTWO <std::string> _c2;
std::string* _strp = _c2.create("Hello");
std::cout << *_strp << '\n';
std::free (_strp);
return 0;
}
上面的代码应该创建一个传递给它的参数数量不同的对象。但是,当我创建一个用std :: string模板化的实例时,传递一个“Hello”参数应该给我一个指向包含“Hello”的字符串的指针。然而,这种情况并非如此。如果您运行上面的代码,前置和后置值将不同,前置值是正确的。有谁知道导致这种不良行为的原因是什么?感谢。
答案 0 :(得分:1)
C ++在底层硬件的原始访问和能够快速开发的高级语言之间处于一个令人不舒服的地方。
一般原则是你不能使用memcpy移动一个你在这种情况下破坏的对象。
创建课程时。
class Example {
protected:
char * ptr;
size_t len;
public:
Example( const char * str ) {
len = strlen( str );
ptr = new char[ len + 1];
}
virtual ~Example() {
delete [] ptr;
}
Example & operator=( const Example & rhs ) {
if( &rhs != this ) {
delete [] ptr;
len = rhs.len();
ptr = new char[ len + 1 ];
strcpy( ptr, rhs.ptr );
}
}
Example( const Example & src ) {
len = src.len;
ptr = new char[ len + 1];
strcpy( ptr, src.ptr );
}
Example() {
ptr = new char[1];
ptr[0] = '\0';
len = 0;
}
};
访问内部状态的想法阻止了类的设计者能够保证正确性。
如果类示例已经memcpy',那么将有两个类的实例,两者都具有值ptr set。如果其中一个被破坏,那么它释放ptr在另一个中寻址的内存,打破其他类的内部状态。
当一个类已经很好地实现时,使用operator =进行复制允许设计者理解可以共享的内容,需要复制的内容,并且可以确保正确的行为。
通过使用原始内存修改或复制类,操作符因此而面向未定义的行为。