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

时间:2010-02-20 18:33:54

标签: c++ constants const-correctness

请考虑以下代码。

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;
}

tconst变量,value()是一个常量成员函数,返回const T&。 AFAIK,const类型不能分配给非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;
}

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

3 个答案:

答案 0 :(得分:6)

因为你有两个间接层 - 在你的main函数中,对value的调用会返回对非const foo的const指针的引用。

这可以安全地复制到非const指针中,指向非const foo

如果您使用test实例化const foo *,那将是另一回事。

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

<强>更新

来自评论:

  

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

只能读取Const数据。它不能写(“变异”)。但是复制一些数据是一种阅读方式,所以没关系。例如:

const int c = 5;
int n = c;

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

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

struct foo { int n; };

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

更新2:

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

const T& value() const

请注意,您在那里引用了const T。所以返回值将是对const:a foo *的引用。它只是指针地址无法修改。它指向的对象可以修改其内容。

在你的第二个例子中,你摆脱了引用部分,它改变了含义并使const修饰符适用于指针指向的对象,而不是应用于指针本身。

答案 1 :(得分:1)

使用以下模板专业化:

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*’

答案 2 :(得分:1)

你的代码没有任何问题,对指针的const引用只意味着你不能修改指针,但指向的对象仍然是完全可变的。如果您在main函数中尝试更改f t成员指向的地址,您将看到不能:封装完全保留。

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

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

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

唯一的解决方案就是像Amit所说的那样,并为T*提供班级的专业化。