具有指针成员且没有重写复制构造函数的类
classes with pointer members and no overridden copy constructor
当指针指向在同一个类中声明的东西时,我认为如果你复制这样一个对象,那么有多组指针,但它们都指向同一个对象,我是否正确?
这是否意味着在其他类实例中有其他对象已经创建,但没有指向?
作为一个侧面的问题,我认为一个共享指针会指向所有的类在一组对象,但在一个安全的方式是正确的吗?
是-当您没有定义复制构造函数时,编译器将为您发出一个-它将做一个浅复制-只是复制值(i。(指针的地址)
所以这两个对象(original和'copy')将有指向同一个对象的指针字段
如果你不深度复制对象,也就是说,如果你不覆盖复制函数并进行浅复制,指针将指向同一个对象的实例。如果随后删除其中一个浅拷贝对象,则其他对象的指针将指向垃圾。如果您以任何方式取消引用它们,您的程序将崩溃。
赋值操作符也会发生同样的情况。当你有指针时,重载它们。
一个例子:
struct Message
{
Message(const LogType_E & type_in = LOG_ERROR, const unsigned int & domain_in = 0, const int & msgId_in = 0, const char * msg_in = "");
int myMsgID; //!< message id
unsigned int myDomain; //!< message domain
LogType_E myType; //!< message type
char * myMsg; //!< actual message
~Message()
{
if(myMsg != NULL) delete [] myMsg;
}
Message(const Message &);
const Message& operator=(const Message & rhs);
};
这是一个"message"类型,用于与其他东西一起保存消息。
实现如下:
Message::Message(const Message & cp_in):myType(cp_in.myType), myDomain(cp_in.myDomain), myMsgID(cp_in.myMsgID), myMsg(NULL)
{
if(cp_in.myMsg != NULL)
{
myMsg = new char[strlen(cp_in.myMsg)+1];
memcpy (myMsg, cp_in.myMsg, strlen(cp_in.myMsg)+1);
}
}
const Message & Message::operator =(const AX::Base::Log::Message &cp_in)
{
if (this == &cp_in) // protect against invalid self-assignment
return *this;
//deallocate old memory
if(myMsg != NULL) delete [] myMsg;
if(cp_in.myMsg != NULL)
{
//allocate new memory and copy the elements
myMsg = new char[strlen(cp_in.myMsg)+1];
memcpy (myMsg, cp_in.myMsg, strlen(cp_in.myMsg)+1);
}
// copy other data members
myType = cp_in.myType;
myDomain = cp_in.myDomain;
myMsgID = cp_in.myMsgID;
return *this;
}
也就是说,请使用std::string
来避免所有这些事情-这只是一个概念证明的例子。
假设您有一个这样的类,它显示了您在问题中提出的问题
class Foo{};
class Bar
{
public:
Foo* mFoo;
Bar() : mFoo( new Foo() ) {}
~Bar() { delete mFoo;}
};
和如下代码
Bar x ;
Bar y = x;
上面的代码会导致核心转储,因为y和x都指向同一个Foo,析构函数会尝试删除同一个Foo两次。
替代1声明但不提供定义,使Bar永远不会是复制构造函数或赋值。这将确保Bar y = x
将有一个链接错误,因为您设计的类不被复制。
class Bar
{
public:
Foo* mFoo;
Bar() : mFoo( new Foo() ) {}
~Bar() { delete mFoo;}
Bar(const Bar &);
Bar& operator= (const Bar &);
};
替代2 提供执行正确操作的复制构造函数和赋值操作符。与编译器提供的复制和赋值的默认实现进行浅复制不同的是,你复制了Foo,这样x和y都有自己的Foo
class Bar
{
public:
Foo* mFoo;
Bar() : mFoo( new Foo() ) {}
~Bar() { delete mFoo;}
Bar(const Bar & src)
{
mFoo = new Foo( *(src.mFoo) );
}
Bar& operator= (const Bar & src)
{
mFoo = new Foo( *(src.mFoo) );
return *this;
}
};
备选方案3 (BEST)
使用c++ 11 shared_ptr或boost并省略复制和赋值作为默认编译器,前提是它会做正确的事情,因为shared_ptr被refcount,并且即使x和y共享相同的Foo,也只会删除Foo一次。还需要注意的是,~Bar
不需要显式清理,因为当Foo的refcount变为零时,mFoo
将在std::shared_ptr<Foo>
析构函数中自动删除。
class Bar
{
public:
std::shared_ptr<Foo> mFoo;
Bar() :mFoo( new Foo() ) {}
~Bar() { }
};
让代码来处理:
struct X
{
int data;
int *ptr;
X() : ptr(&data) {}
};
X a;
X b = a; // yes, `a.ptr` points to `b.data`!
实际上,指针将被逐字复制,并将继续指向副本的源。
使用pointer-to-members
可以解决的:
struct X
{
int data;
int X::*ptr;
X() : ptr(&X::data) {}
};
X a;
X b = a; // now, `a.ptr` points to `a.data`
用更多的用法提示扩展这个示例https://ideone.com/F0rC3
a.ptr = &X::data2; // now `a.ptr` points to `a.data2`
// `b.ptr` points to `b.data1`
b = a; // `b.ptr` points to `b.data2` too
// Usage hint:
int deref = a.*(a.ptr); // gets the field pointed to by a.ptr, from the instance a
deref = b.*(b.ptr); // gets the field pointed to by b.ptr, from the instance b
// but of course you could get fancy and do
deref = a.*(b.ptr); // gets the field pointed to by b.ptr, **but** from the instance a
这可能是你想要的。虽然,为什么你想要超出了我的理解(可能也超出了c++的理解)
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 当从函数参数中的临时值调用复制构造函数时
- 如果有一个模板构造函数只有一个泛型参数,为什么我必须有一个复制构造函数
- 为什么需要复制构造函数,在哪些情况下它们非常有用
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 为什么类中的ostringstream类型的成员会导致";调用隐含删除复制构造函数";错误
- 复制构造函数、赋值运算符C++
- std::ofstream 作为类成员删除复制构造函数?
- 复制构造函数C++无法正确复制指针
- 关于复制构造函数的一个棘手问题
- 为什么调用复制构造函数而不是移动构造函数?
- 填充上编译器生成的复制构造函数之间的不一致
- C++ 对象指针数组的复制构造函数
- C++ 基本 CTOR 说明 - 为什么不调用赋值/复制构造函数
- 防止在复制构造函数中隐式调用基构造函数
- 为用户定义的类正确调用复制构造函数/赋值运算符
- 具有已删除移动和复制构造函数的类的就地构造
- 复制构造函数隐式转换问题
- 复制构造函数中的递归调用