c ++中的指针赋值

时间:2014-12-08 05:26:17

标签: c++ pointers

我有一个简单的结构来容纳两个const double s。

struct Scale {
    const double SCALE_X, SCALE_Y;

    Scale(double, double);
};

Scale::Scale(double sx, double sy) :
SCALE_X(sx), SCALE_Y(sy) {
}

我有这个函数返回一个布尔值作为确认,并将传递的oscale指针设置为内部找到的任何计算值。

bool FindSequence(Scale* oscale) {
    // ...
    *oscale = Scale(sx, sy);
    // ...
    return true;
}

使用中:

Scale *scale;
if (FindSequence(scale)) {
    std::cout << "Yes" << std::endl;
}

编译日志:

photon.cpp:286:14: error: use of deleted function 'photon::Scale& photon::Scale::operator=(photon::Scale&&)'
      *oscale = Scale(sx, sy);
              ^
In file included from photon.h:5:0,
                 from photon.cpp:4:
globals.h:76:9: note: 'photon::Scale& photon::Scale::operator=(photon::Scale&&)' is implicitly deleted because the default definition would be ill-formed:
  struct Scale {
         ^
globals.h:76:9: error: non-static const member 'const double photon::Scale::SCALE_X', can't use default assignment operator
globals.h:76:9: error: non-static const member 'const double photon::Scale::SCALE_Y', can't use default assignment operator

我是否必须覆盖运营商=?是因为Scale结构是不可变的吗?我做错了什么?

3 个答案:

答案 0 :(得分:2)

这里有几个问题。我会一个接一个地过去。

const double SCALE_X, SCALE_Y;

这是您问题的主要来源。如果类具有const成员,则编译器不会生成复制构造函数或复制赋值运算符;你必须自己生成它们。

但是,我认为这些成员甚至不应该const。如果某人有Scale个对象,那么他们应该可以更改其值,但如果他们有const Scale个对象,那么他们将无法能够,因为所有(非mutable)数据成员在const对象上访问时“变为”const

换句话说,让类的使用者决定他们是否希望实例是只读的;非const Scale个对象应该是可变的!

通过这一次更改,编译器将能够生成一个复制构造函数和一个理智的复制赋值运算符,以便特定错误消失。

但是,你在这里有另一个错误:

Scale *scale;
if (FindSequence(scale)) {

您正在传入未初始化的指针。只要FindSequence()取消引用此指针,就会调用未定义的行为,并且您的程序可能会崩溃。

通常你会使用引用来做到这一点:

bool FindSequence(Scale & oscale) {

然后调用代码变成了这个(只需删除*):

Scale scale;
if (FindSequence(scale)) {

但要做 this ,你需要一个默认的构造函数。一个理智的选择是将成员初始化为零:

Scale::Scale() : SCALE_X(0), SCALE_Y(0) { }

(或者,您可以改为Scale scale(0, 0);。)

应用这三个更改,编译器应该解决这些问题。 (当然,它可能遇到其他问题,但这些更改将解决您问题中的问题。)

答案 1 :(得分:0)

这里有两点需要注意

第一个编译器不会为类生成赋值运算符,它不知道如何进行赋值,即包含const和引用成员的类。

其次,你试图取消引用未初始化的指针,这很糟糕。

答案 2 :(得分:0)

我补充说,如果你确实确实想要const成员和初始化功能,那么这样做的方法是放置新:

bool FindSequence(Scale* oscale) {
    // ...
    oscale = new (oscale) Scale(sx, sy);
    // ...
    return true;
}

这使用您的Scale构造函数来初始化指向对象,而不是赋值运算符,从而避免使用编译器生成的运算符。

正如其他人所指出的那样,您的代码会遇到未定义的行为,因为您将未初始化的指针传递给FindSequence函数。你可能的意思是这样的:

Scale scale(0.0, 0.0);
if (FindSequence(&scale)) {
    std::cout << "Yes" << std::endl;
}

有些人认为这是一个坏主意,因为它允许你在初始化之后更改const对象,并且我希望你的编译器可以在假设那些{{const double的假设下进行优化。 1}}成员不会改变,所以如果你尝试这个,你可能会看到奇怪的行为。