C++ 治疗向量<;int*>;作为向量<;常数int*>;不复制(C+;+;0x)

C++ 治疗向量<;int*>;作为向量<;常数int*>;不复制(C+;+;0x),c++,constants,accessor,C++,Constants,Accessor,一个类包含一个std::vector。外部代码需要对此向量进行只读访问,不能修改内容(指针或其内容)。在类内部,值可能会更改(例如,double_values()),因此无法将它们存储为std::vector 有没有一种方法可以将std::vector作为std::vector返回,而不进行复制?感觉应该有,因为const只是在编译时操作,说明什么可以修改,什么不能修改 代码:(使用g++-std=c++0x编译) 类只读访问 { 公众: 只读访问(const std::vector和int_p

一个类包含一个
std::vector
。外部代码需要对此向量进行只读访问,不能修改内容(指针或其内容)。在类内部,值可能会更改(例如,
double_values()
),因此无法将它们存储为
std::vector

有没有一种方法可以将
std::vector
作为
std::vector
返回,而不进行复制?感觉应该有,因为const只是在编译时操作,说明什么可以修改,什么不能修改

代码:(使用g++-std=c++0x编译)

类只读访问
{
公众:
只读访问(const std::vector和int_ptrs_param):
int_ptrs(int_ptrs_参数)
{
}
常量std::vector&get_int_ptrs()常量
{
返回整数;
}
std::vector安全获取int ptrs()常量
{
//无法编译(太糟糕了):
//返回整数;
//需要复制整个向量吗
向量结果(int_ptrs.size());

for(int k=0;k如果仍要保留常量指针,返回向量将意味着一个副本

但是,如果您的目标是提供一种在不修改值或修改其容器的情况下使用值的方法,那么基于访问者模式的算法可能是一个非常好的解决方案,特别是现在我们可以使用lambda表达式:

#include <vector>
#include <iostream>

class Data
{
public:

    //...whatever needed to fill the values

    // here we assume that Func is equivalent to std::function< void ( int )> or std::function< void (const int& ) > and can return anything that will be ignored here.
    template< class Func > 
    void for_each_value( Func func ) const // read-only
    {
        for( const int* value : m_values ) // implicit conversion
        {
             func( *value ); // read-only reference (const &), or copy
             // if func needs to work with the adress of the object, it still can by getting a reference to it and using & to get it's adress
        }
    }


    void print() const
    {
        std::cout << "\nData values: \n";
        for_each_value( []( const int value ) { std::cout << "    "<< value << '\n'; } );
    }

    void count_values() const { return m_values.size(); }

private:

    std::vector<int*> m_values;

};



int main()
{
    Data data;
    // ... whatever needed to fill the data

    data.print();    

    std::vector<int> modified_values;
    data.for_each_value( [&]( int value ) { modified_values.push_back( value + 42 ); } );

    return 0;
}
#包括
#包括
类数据
{
公众:
//…填充值所需的任何内容
//这里我们假设Func等价于std::function或std::function并且可以返回任何在这里被忽略的内容。
模板
每个值(Func Func)常量//只读时为空
{
for(const int*value:m_value)//隐式转换
{
func(*value);//只读引用(const&),或复制
//如果func需要处理对象的地址,它仍然可以通过获取对它的引用并使用&来获取它的地址
}
}
void print()常量
{

std::cout您可以通过自定义迭代器提供常量值的视图。一种简单的方法是使用
boost::iterator

#include <boost/iterator/indirect_iterator.hpp>

class ReadOnlyAccess
{
// ...
    typedef boost::indirect_iterator<const int* const*, const int> const_val_iter_type;
    const_val_iter_type cval_begin() {
        return it_t{const_cast<const int* const*>(&int_ptrs[0])};
    }
}

int main() {
    // ...
    auto x = roa.cval_begin();
    std::cout << x[0] <<' ' << x[1] << x[2] <<'\n';
    // we can still access the pointers themselves via .base() member function:
    for (int i=0; i<3; ++i)
        assert(x.base()[i] == safe_int_ptrs[i]);
    // the values are read-only, the following does not compile:
    // x[0] = -1;
    // **x.base() = -1;
    // *x.base() = nullptr;
}
#包括
类ReadOnlyAccess
{
// ...
typedef boost::间接迭代器const\u val\u iter\u type;
const_val_iter_类型cval_begin(){
返回它{const_cast(&int_ptrs[0]);
}
}
int main(){
// ...
auto x=roa.cval_begin();

std::不可能重复see@Bo:这个问题并不能回答这个问题,真的。而且WeaselOx也不相关,因为指针是间接的。@Xeo-另一个问题的答案告诉我们为什么它不起作用。还有什么其他类型的答案?一个高级概念性的解决方案是可以接受的。您如何允许使用ut更改代码中的内容?是否有办法制作副本(感觉没有必要,这可能是限制性能的因素)。我可以简单地执行一个
void*
cast,但我担心这是一个糟糕的设计。Oviously。你到底为什么要问这个问题?这里std::for_在类外使用的每个都不会有帮助,因为它需要公开真正的容器迭代器,或者制作一个副本,这是可以避免的。我只能用std::对于_,没有任何好处。我的答案是没有容器的副本,无论遍历的算法是什么,如果你知道类的用户需要什么样的遍历,你就不需要公开类的内容。显然,如果你不知道,就接受YAGNI。也就是说,有些情况下需要类通过迭代器公开内容。但我不认为这对于特定的问题是必要的。那么,如果迭代器没有公开,您的for range循环将如何工作?如果是,您的
for_each_值
std::for_each
有何不同?YAGNI很好,但对我来说,您正在颠倒应用它。为什么当标准库已经为您提供了功能时,您可以为每个
函数提供自己的
。看起来我不理解您的问题,因为我认为我已经回答了上面的问题。或者我们讨论的是同一个循环?我是说,公开迭代器是好的,如果这是类型的目的,我补充说,我不这么认为在这里是合适的。类型不是容器,它包含一个容器。它不应该在没有控制的情况下公开它的数据。
#include <boost/iterator/indirect_iterator.hpp>

class ReadOnlyAccess
{
// ...
    typedef boost::indirect_iterator<const int* const*, const int> const_val_iter_type;
    const_val_iter_type cval_begin() {
        return it_t{const_cast<const int* const*>(&int_ptrs[0])};
    }
}

int main() {
    // ...
    auto x = roa.cval_begin();
    std::cout << x[0] <<' ' << x[1] << x[2] <<'\n';
    // we can still access the pointers themselves via .base() member function:
    for (int i=0; i<3; ++i)
        assert(x.base()[i] == safe_int_ptrs[i]);
    // the values are read-only, the following does not compile:
    // x[0] = -1;
    // **x.base() = -1;
    // *x.base() = nullptr;
}