C++ 复制构造函数不复制
C++ Copy constructor does not copy
我正在尝试使用复制构造函数将一个对象初始化为另一个对象。我很困惑,如果我注释掉复制构造函数,它会很好地初始化,但使用以下代码却不会。
class TDateTime : public TData {
public:
TDateTime() : TData(EDataStateInvalid) {}
TDateTime(const tm& aTm){};
TDateTime(int aTm_sec, int aTm_min, int aTm_hour,
int aTm_mday, int aTm_mon, int aTm_year, int aTm_wday,int aTm_isdst){
value.tm_sec=aTm_sec;
value.tm_min=aTm_min;
value.tm_hour=aTm_hour;
value.tm_mday=aTm_mday;
value.tm_mon=aTm_mon;
value.tm_year=aTm_year;
value.tm_wday=aTm_wday;
value.tm_isdst=aTm_isdst;
};
virtual ~TDateTime() {cout<<"Destroying TDateTime ";};
//! Copy constructor
TDateTime(const TDateTime& aInstance){};
//! Copies an instance
virtual const TDateTime& operator=(const TDateTime& aInstance){return *this;};
private:
tm value;
};
main.cpp
tm=createDateTime(x);
TDateTime aDateTimeFrom(tm.tm_sec,tm.tm_min,tm.tm_hour,tm.tm_mday,tm.tm_mon,tm.tm_year,tm. tm_wday,0);
TDateTime aDateTimeTo(aDateTimeFrom);
如果我注释掉复制构造函数,它复制得很好。如果我删除 {} 那么编译器会抱怨未定义的符号。
你能指出这里出了什么问题吗?
基于关于空复制构造函数什么都不做的回答,我将其注释掉并且复制是完美的,但我还有另一个问题。如果我这样做
TDateTime aDateTime;
aDateTime=aDateTimeFrom;
aDateTime 具有所有垃圾值。对此有任何指示吗?
编译器生成一个复制构造函数,如果用户没有声明复制构造函数,它会执行 member-wise 复制。如果用户确实声明了 copy-constructor,那么复制构造函数会执行用户告诉它的操作,在您的情况下 - 完全没有。
TDateTime(const TDateTime& aInstance){ /* empty body*/};
//! Copy constructor
TDateTime(const TDateTime& aInstance){};
你的复制构造函数什么都不做。 user-written 复制构造函数没有魔法;如果你不让他们做任何事情,那么他们就不会做任何事情。
更准确地说, 创建了一个新实例,但其成员未初始化或 default-initialised。
当我们在做的时候...
//! Copies an instance
virtual const TDateTime& operator=(const TDateTime& aInstance){return *this;};
同样的问题。您的 copy-assignment 操作员不执行任何操作。
按照惯例,它也不应该 return 一个 const
参考,而是一个非 const
参考。
值得一提的是,您的直觉似乎是正确的,因为您的目标确实应该是创建不需要任何 self-written 复制构造函数或 [=45] 的 classes =] 运算符,因为所有成员都知道如何正确复制或 copy-assign 自己(如 std::string
或 std::vector
或 std::shared_ptr
)。但在那种情况下,与其定义具有空实现的成员函数,不如根本不在代码中声明它们,这样编译器就可以自动处理所有事情。
最后,还有一件事:C++ classes 的一个很好的经验法则是它们应该 具有虚函数并禁用复制(有时称为 "identity classes") 或没有虚函数并且允许复制(有时称为"value classes")。像虚拟赋值运算符这样的东西通常表示过于复杂,hard-to-use 和 error-prone class 设计。
您定义了一个不执行任何操作的复制构造函数。
在您的情况下,您实际上并不需要复制构造函数 and/or 复制赋值运算符,编译器生成的版本就足够了(明智的做法是 sure/recheck tm class 可以处理复制)。
有一个rule of three,它指出如果定义析构函数,则需要复制构造函数和复制赋值运算符。但这只是一个经验法则,并非实际需要。在您的情况下,不涉及内存管理,您仅将析构函数用于日志记录。
所以根本不要声明复制构造函数(顺便说一下,您的赋值运算符也有同样的缺陷 - 它不复制任何东西)并让编译器完成工作。
我正在尝试使用复制构造函数将一个对象初始化为另一个对象。我很困惑,如果我注释掉复制构造函数,它会很好地初始化,但使用以下代码却不会。
class TDateTime : public TData {
public:
TDateTime() : TData(EDataStateInvalid) {}
TDateTime(const tm& aTm){};
TDateTime(int aTm_sec, int aTm_min, int aTm_hour,
int aTm_mday, int aTm_mon, int aTm_year, int aTm_wday,int aTm_isdst){
value.tm_sec=aTm_sec;
value.tm_min=aTm_min;
value.tm_hour=aTm_hour;
value.tm_mday=aTm_mday;
value.tm_mon=aTm_mon;
value.tm_year=aTm_year;
value.tm_wday=aTm_wday;
value.tm_isdst=aTm_isdst;
};
virtual ~TDateTime() {cout<<"Destroying TDateTime ";};
//! Copy constructor
TDateTime(const TDateTime& aInstance){};
//! Copies an instance
virtual const TDateTime& operator=(const TDateTime& aInstance){return *this;};
private:
tm value;
};
main.cpp
tm=createDateTime(x);
TDateTime aDateTimeFrom(tm.tm_sec,tm.tm_min,tm.tm_hour,tm.tm_mday,tm.tm_mon,tm.tm_year,tm. tm_wday,0);
TDateTime aDateTimeTo(aDateTimeFrom);
如果我注释掉复制构造函数,它复制得很好。如果我删除 {} 那么编译器会抱怨未定义的符号。
你能指出这里出了什么问题吗? 基于关于空复制构造函数什么都不做的回答,我将其注释掉并且复制是完美的,但我还有另一个问题。如果我这样做
TDateTime aDateTime;
aDateTime=aDateTimeFrom;
aDateTime 具有所有垃圾值。对此有任何指示吗?
编译器生成一个复制构造函数,如果用户没有声明复制构造函数,它会执行 member-wise 复制。如果用户确实声明了 copy-constructor,那么复制构造函数会执行用户告诉它的操作,在您的情况下 - 完全没有。
TDateTime(const TDateTime& aInstance){ /* empty body*/};
//! Copy constructor TDateTime(const TDateTime& aInstance){};
你的复制构造函数什么都不做。 user-written 复制构造函数没有魔法;如果你不让他们做任何事情,那么他们就不会做任何事情。
更准确地说, 创建了一个新实例,但其成员未初始化或 default-initialised。
当我们在做的时候...
//! Copies an instance virtual const TDateTime& operator=(const TDateTime& aInstance){return *this;};
同样的问题。您的 copy-assignment 操作员不执行任何操作。
按照惯例,它也不应该 return 一个 const
参考,而是一个非 const
参考。
值得一提的是,您的直觉似乎是正确的,因为您的目标确实应该是创建不需要任何 self-written 复制构造函数或 [=45] 的 classes =] 运算符,因为所有成员都知道如何正确复制或 copy-assign 自己(如 std::string
或 std::vector
或 std::shared_ptr
)。但在那种情况下,与其定义具有空实现的成员函数,不如根本不在代码中声明它们,这样编译器就可以自动处理所有事情。
最后,还有一件事:C++ classes 的一个很好的经验法则是它们应该 具有虚函数并禁用复制(有时称为 "identity classes") 或没有虚函数并且允许复制(有时称为"value classes")。像虚拟赋值运算符这样的东西通常表示过于复杂,hard-to-use 和 error-prone class 设计。
您定义了一个不执行任何操作的复制构造函数。
在您的情况下,您实际上并不需要复制构造函数 and/or 复制赋值运算符,编译器生成的版本就足够了(明智的做法是 sure/recheck tm class 可以处理复制)。
有一个rule of three,它指出如果定义析构函数,则需要复制构造函数和复制赋值运算符。但这只是一个经验法则,并非实际需要。在您的情况下,不涉及内存管理,您仅将析构函数用于日志记录。
所以根本不要声明复制构造函数(顺便说一下,您的赋值运算符也有同样的缺陷 - 它不复制任何东西)并让编译器完成工作。