关于类对象的编译器行为我不知道';我不明白 我是NoOB,仍然在学习C++语言。问题是,在做一本书中的练习时,我遇到了一个我不理解的编译器行为
头文件关于类对象的编译器行为我不知道';我不明白 我是NoOB,仍然在学习C++语言。问题是,在做一本书中的练习时,我遇到了一个我不理解的编译器行为,c++,class,compiler-construction,constructor,destructor,c++11,C++,Class,Compiler Construction,Constructor,Destructor,C++11,头文件 // stock10.h -- Stock class declaration with constructors, destructor added #ifndef STOCK10_H_ #define STOCK10_H_ #include <string> class Stock { private: std::string company; long shares; double share_val; double total_v
// stock10.h -- Stock class declaration with constructors, destructor added
#ifndef STOCK10_H_
#define STOCK10_H_
#include <string>
class Stock
{
private:
std::string company;
long shares;
double share_val;
double total_val;
void set_tot() { total_val = shares * share_val; }
public:
// two constructors
Stock(); // default constructor
Stock(const std::string & co, long n = 0, double pr = 0.0);
~Stock(); // noisy destructor
void buy(long num, double price);
void sell(long num, double price);
void update(double price);
void show();
};
#endif
编译器不应该:1.使用构造函数创建临时对象
2.将该对象分配给stock1对象
3.销毁临时对象 信息不是应该说漂亮的食物而不是纳米智能吗
我不明白。有什么帮助吗?您没有定义赋值运算符,因此如果您使用的是C++11编译器,它可能会使用移动赋值运算符,该运算符交换对象,然后删除临时对象的新内容,临时对象以前位于
stock1
中
至少,这是观察到的行为。然而,ecatmur是正确的,您的类不应该收到隐式移动赋值运算符。这当然可能是一个编译器错误。我看不出您的代码有什么直接的错误,但您可能应该实现一个复制构造函数和赋值运算符,以确保复制操作正确执行 大概是这样的:
class Stock
{
// ...
public:
// ...
Stock(const Stock &other)
: company(other.company), shares(other.shares),
share_val(other.share_val), total_val(other.total_val)
{ }
Stock &operator=(const Stock &other)
{
company = other.company;
shares = other.shares;
share_val = other.share_val;
total_val = other.total_val;
return *this;
}
// ...
};
有关复制构造函数的更多信息,请参见例如。对于赋值运算符,请参见,例如:您尚未编写复制赋值运算符
Stock::operator=(const Stock&)
或移动赋值运算符Stock::operator=(Stock&&)
,因此您的赋值stock1=Stock(“俏皮食品”,10,50.0)代码>将调用隐式定义的复制/移动分配运算符:
12.8复制和移动类对象[class.copy]
18-如果类定义未显式声明副本赋值运算符,则隐式声明一个。如果
类定义声明一个移动构造函数或移动赋值运算符,即隐式声明的副本
分配操作员定义为已删除;否则,它被定义为默认值(8.4)。
28-非联合类X的隐式定义的复制/移动赋值运算符执行成员复制-
/移动其子对象的指定
由于类具有用户定义的析构函数,因此不会隐式定义移动分配运算符(12.8:20),因此将调用隐式定义的复制分配运算符:
20-如果类X的定义没有显式声明移动赋值运算符,则会隐式声明移动赋值运算符
声明为默认的当且仅当[…]
- X没有用户声明的析构函数
因此,库存(“俏皮食品”,10,50.0)
将以成员身份复制到stock1
中,然后销毁;因此,显示的消息将是“再见,漂亮的食物!”
这里有一个SSCCE:
#include <iostream>
#include <string>
struct S {
std::string s;
S(const std::string &s): s(s) { std::cout << "S(" << s << ")\n"; }
~S() { std::cout << "~S(" << s << ")\n"; }
};
int main() {
S a("a");
a = S("b");
}
在我们回答你的问题之前,你最好给我们看看你的班级。至少是类声明、复制构造函数和赋值运算符(如果您实现了一个,那么您可能应该实现它)。@Joachim Pileborg对此表示抱歉。我添加了类实现文件。您能同时添加头文件吗?我们可能还需要看看您如何声明类成员变量。我无法重现您的输出。再见,漂亮的食物代码>。输出不匹配<代码>“将stock1分配给stock2:\n”未显示。请发布实际输出。但我不是在创建对象。它已经创建了。在你的例子中是bar=Foo(某物)。酒吧已经开张了created@Kurospidey当你做
stock1=Stock(“美味食品”,10,50.0)代码>,编译器将创建一个临时对象,然后使用stock1
的赋值运算符复制临时对象。如果您没有自己的赋值运算符,那么编译器生成的赋值运算符可能会做错误的事情。@JoachimPileborg,我理解。但在那之后,它不应该摧毁那个临时物体吗?所以信息应该是“再见,俏皮食品”,因为它正在破坏公司名为俏皮食品的物体。相反,它会说“再见,NanoSmart”,就像它正在销毁stock1对象一样,这不值得担心,我指的是赋值运算符。不过也是一样。请注意,使用“移动指定”操作符后,temp对象可能很好地保存了stock1
以前的内容。@christorcreutzig移动赋值运算符根据12.8:20被用户声明的析构函数抑制。仅执行默认构造函数/赋值的复制构造函数/赋值是多余的,并且可能是错误源。如果类没有指针成员,通常不需要它们。谢谢你的回答。问题是,我在学习语言的同时,正在跟随一本书。在这个特别的练习中,作者声称程序输出应该是我现在使用的工具。我认为也应该是这个问题,但编译器不这么认为,我不知道为什么。@同上,在这种情况下,编译器默认值显然有错误,否则OP不会发布问题。@JoachimPileborg,你试过OP的代码吗?你是否重现了OP的异常结果,你的建议是否为你修复了它?对我来说,OP的代码工作正常,没有任何更改。问题是,为什么不显示该消息。OP索赔再见,NanoSmart“代码>已打印。@juanchopanza OP不正确或正在使用不一致的实现。看起来是这样的。”。我还不能在各种GCC上复制它。谢谢大家的评论。我正在使用mingw(可能是一个奇怪的版本)
stock1 = Stock("Nifty Foods", 10, 50.0); // temp object
class Stock
{
// ...
public:
// ...
Stock(const Stock &other)
: company(other.company), shares(other.shares),
share_val(other.share_val), total_val(other.total_val)
{ }
Stock &operator=(const Stock &other)
{
company = other.company;
shares = other.shares;
share_val = other.share_val;
total_val = other.total_val;
return *this;
}
// ...
};
#include <iostream>
#include <string>
struct S {
std::string s;
S(const std::string &s): s(s) { std::cout << "S(" << s << ")\n"; }
~S() { std::cout << "~S(" << s << ")\n"; }
};
int main() {
S a("a");
a = S("b");
}
S(a)
S(b)
~S(b)
~S(b)