简体   繁体   English

在返回指针的Getter上进行数组访问,这是不好的做法吗?

[英]Array access on a Getter that returns a pointer, is that bad practice?

Imagine the following scenario: 想象以下情况:

class A 
{
    int a[50];
    int* GetAPtr() { return a; };
};
...
A b;
if(b.GetAPtr()[22] == SOME_RANDOM_DEFINE) do_this_and_that();

Is this kind of access considered bad practice? 这种访问是否被视为不良做法? b.GetAPtr()[22] b.GetAPtr()[22]

To clarify my situation: 为了澄清我的情况:
1. I cannot use new/malloc in this case, the array muste be static 1.在这种情况下,我不能使用new / malloc,数组必须是静态的
2. This is meant to encapsulate older C code that uses multiple arrays where this comes extremly handy 2.这是为了封装使用多个数组的旧C代码,这非常方便
3. I know that returning a pointer can possibly return a NULL pointer, we do not talk about that issue here 3.我知道返回一个指针可能会返回一个NULL指针,在此我们不讨论该问题。

If you really need such const expression you could make it into a function: 如果您确实需要这样的const表达式,则可以将其转换为函数:

class A 
{
    int a[50];
    bool check_this_and_that() { return a[22] == SOME_RANDOM_DEFINE; };
};
...
A b;
if(b.check_this_and_that()) do_this_and_that();

magic numbers are bad in general but inside a class logic it's more forgiveable and outsiders don't have to see this. 魔术数字通常是不好的,但是在类逻辑中它是更可原谅的,外来者不必看到这一点。

Yes, it is bad practice, because you have no way of knowing how long the array is. 是的,这是不好的做法,因为您无法知道数组的长度。 You could follow the idiomatic standard library approach and return begin and end pointers, pointing to the first and one-past-last elements. 您可以遵循惯用的标准库方法,并返回beginend指针,指向第一个和最后一个元素。

class A 
{
    int a[50];
    int* begin() { return &a[0]; };
    int* end() { return &a[50]; };
    const int* begin() const { return &a[0]; };
    const int* end() const { return &a[50]; };
    size_t size() const { return 50; } // this could be handy too
};

As well as giving you the tools to iterate over the elements like you would over a standard library container, this allows you to check whether any pointer to an element of the array is < v.end() . 除了像在标准库容器上一样为您提供迭代元素的工具外,这还允许您检查指向数组元素的指针是否为< v.end() For example 例如

it* it = b.begin() + 22;
if(it < b.end() && *it == SOME_RANDOM_DEFINE) do_this_and_that();

This makes it trivial to use standard library algorithms: 这使得使用标准库算法变得很简单:

A b;
// fill with increasing numbers
std::iota(b.begin(), b.end());
// sort in descending order
std::sort(s.begin(), s.end(), std::greater<int>());

// C++11 range based for loop
for (auto i : b) 
  std::cout << i << " ";
std::endl;

GetAPtr is a method for accessing a private data member. GetAPtr是一种用于访问私有数据成员的方法。 Now ask yourself what are the advantages of b.GetAPtr()[22] over ba[22] ? 现在问问自己b.GetAPtr()[22]ba[22]什么优势?

Encapsulating data is a good way to maintain constraints on and between data members. 封装数据是维持数据成员之间和成员之间约束的好方法。 In your case there is at least a correlation between the a array and its length 50 . 在你的情况下,存在至少之间的相关a阵列和它的长度50

Depending on the use of A you could build a interface providing different access patterns: 根据A的使用,您可以构建一个提供不同访问模式的接口:

class A {
   int a[50];
public:
   // low level
   int atA(unsigned i) const { return a[i]; }
   // or "mid" level
   int getA(unsigned i) const { if(i >= 50) throw OutOfRange(); return a[i]; };
   // or high level
   bool checkSomething() const { return a[22] == SOME_RANDOM_DEFINE; }
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM