const 正确性和返回值 - C++

发布于 2024-08-22 06:37:59 字数 850 浏览 9 评论 0原文

请考虑以下代码。

struct foo
{
};

template<typename T>
class test
{
public:   

    test() {} 

    const T& value() const
    {
        return f;
    }

private:
    T f;
};


int main()
{
    const test<foo*> t;
    foo* f = t.value();
    return 0;
}

t 是一个 const 变量,value() 是一个常量成员函数,它返回 const T&。 AFAIK,const 类型不能分配给非常量类型。但是 foo* f = t.value(); 如何编译良好。这是如何发生的以及如何确保 value() 只能分配给 const foo*

编辑

我发现,这种情况发生在使用模板时。以下代码按预期工作。

class test
{
public:   

    test() {} 

    const foo* value() const { return f; }

private:
    foo* f;
};


int main()
{
    const test t;
    foo* f = t.value(); // error here
    return 0;
}

为什么使用模板时会出现问题?

Please consider the following code.

struct foo
{
};

template<typename T>
class test
{
public:   

    test() {} 

    const T& value() const
    {
        return f;
    }

private:
    T f;
};


int main()
{
    const test<foo*> t;
    foo* f = t.value();
    return 0;
}

t is a const variable and value() is a constant member-function which returns const T&. AFAIK, a const type is not assignable to a non-const type. But how foo* f = t.value(); compiles well. How this is happening and how can I ensure value() can be only assigned to const foo*?

Edit

I found that, this is happening on when templates are used. Following code works as expected.

class test
{
public:   

    test() {} 

    const foo* value() const { return f; }

private:
    foo* f;
};


int main()
{
    const test t;
    foo* f = t.value(); // error here
    return 0;
}

Why the problem is happening when templates are used?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

琉璃梦幻 2024-08-29 06:37:59

因为您有两个间接级别 - 在主函数中,对 value 的调用返回对指向非 const foo 的 const 指针的引用。

这可以安全地复制到指向非常量 foo 的非常量指针中。

如果您使用 const foo * 实例化 test,那么情况就会不同。

const test<const foo*> t;
foo* f = t.value(); // error
const foo* f = t.value(); // fine
return 0;

更新

来自评论:

value() 返回 const T&这可以
只能分配给另一个 const
类型。但在这种情况下,编译器是
安全地允许转换。

const 数据只能读取。它无法被写入(“变异”)。不过复制一些数据也是读取的一种方式,所以也没关系。例如:

const int c = 5;
int n = c;

这里,我在c中有一些const数据,我将这些数据复制到一个非常量变量n中。没关系,只是读取数据而已。 c 中的值尚未修改。

现在,假设您的 foo 中有一些数据:

struct foo { int n; };

如果我有一个指向其中之一的非常量指针,我可以通过该指针修改 n 值。您要求 test 模板存储指向非常量 foo 的指针,然后创建 test 的 const 实例。因此,只有指针地址是恒定的。没有人可以更改 test 内部指针中存储的地址,因此无法使其指向另一个对象。但是,它指向的对象可以修改其内容。

更新 2:

当您制作该示例的非模板版本时,您犯了一个错误。为了得到正确的结果,您需要将 foo * 替换为每个有 T 的地方。

const T& value() const

请注意,您在那里有一个对 const T 的引用。因此返回值将是对 const 的引用:a foo *。只是指针地址不能修改。它指向的对象可以修改其内容。

在第二个示例中,您删除了引用部分,这改变了含义并使 const 修饰符应用于指针指向的对象,而不是应用于指针本身。

Because you have two levels of indirection - in your main function, that call to value returns a reference to a const pointer to a non-const foo.

This can safely be copied into non-const pointer to a non-const foo.

If you'd instantiated test with const foo *, it would be a different story.

const test<const foo*> t;
foo* f = t.value(); // error
const foo* f = t.value(); // fine
return 0;

Update

From the comment:

value() returns const T& which can
only be assigned to another const
type. But in this case, compiler is
safely allowing the conversion.

Const data can only be read. It cannot be written ("mutated"). But copying some data is a way of reading it, so it's okay. For example:

const int c = 5;
int n = c;

Here, I had some const data in c, and I copied the data into a non-const variable n. That's fine, it's just reading the data. The value in c has not been modified.

Now, suppose your foo had some data in it:

struct foo { int n; };

If I have a non-const pointer to one of those, I can modify the n value through the pointer. You asked your test template to store a pointer to a non-const foo, and then made a const instance of test. Only the pointer address is constant, therefore. No one can change the address stored in the pointer inside test, so it cannot be made to point to another object. However, the object it points to can have its contents modified.

Update 2:

When you made your non-template version of the example, you made a mistake. To get it right, you need to substitute foo * into each place where there's a T.

const T& value() const

Notice that you have a reference to a const T there. So the return value will be a reference to something const: a foo *. It's only the pointer address that can't be modified. The object it points to can have its contents modified.

In your second example, you got rid of the reference part, which changes the meaning and makes the const modifier apply to the object that the pointer points to, instead of applying to the pointer itself.

芯好空 2024-08-29 06:37:59

使用以下模板专门化:

template<typename T>
class test<T*>
{
public:

    test() {}

    const T* value() const
    {
        return f;
    }

private:
    T* f;
};

包含此后,g++ 会说:

d.cpp: In function ‘int main()’:
d.cpp:41: error: invalid conversion from ‘const foo*’ to ‘foo*’

Use the following template specialization:

template<typename T>
class test<T*>
{
public:

    test() {}

    const T* value() const
    {
        return f;
    }

private:
    T* f;
};

After including this, g++ says:

d.cpp: In function ‘int main()’:
d.cpp:41: error: invalid conversion from ‘const foo*’ to ‘foo*’
纵情客 2024-08-29 06:37:59

您的代码中没有任何问题,对指针进行常量引用仅意味着您无法修改指针,但指向的对象仍然完全可变。如果在您的 main 函数中尝试更改 tf 成员所指向的地址,您会发现不能:封装保存完好。

这与使以下代码有效的原理相同:

void foo(std::vector<int *> const & v)
{
    *v[0] = 0; // op. [] returns const & to int *
}

刚接触 C++ 的人通常会对这种行为感到惊讶,因为对他们来说 const 向量不应该允许修改其元素。事实上它不会,因为存储在向量中的指针不会改变(它保持指向相同的地址)。它是被修改的指向对象,但向量并不关心它。

唯一的解决方案是按照 Amit 所说的那样,为 T* 提供类的专门化。

There's nothing wrong in your code, having a const reference to a pointer only means that you can't modify the pointer, but the pointed-to object remains perfectly mutable. If inside your main function you try to change the address pointed to by the f member of t you'll see that you can't: encapsulation is perfectly preserved.

This is the same principle that makes the following code valid:

void foo(std::vector<int *> const & v)
{
    *v[0] = 0; // op. [] returns const & to int *
}

People new to C++ are usually surprised by this behavior, because for them a const vector should not allow the modification of its elements. And in fact it doesn't, because the pointer stored in the vector does not change (it keeps pointing to the same address). It's the pointed-to object which is modified, but the vector does not care about that.

The only solution is to do as Amit says and provide a specialization of your class for T*.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文