Why is the size of my class zero? How can I ensure

2019-06-27 10:20发布

I created a class but its size is zero. Now, how can I be sure that all objects have different addresses? (As we know, empty classes have a non-zero size.)

#include<cstdio>
#include<iostream>
using namespace std;
class Test
{
    int arr[0];//Why is the sizezero?
};

int main()
{
    Test a,b;  
      cout <<"size of class"<<sizeof(a)<<endl;
       if (&a == &b)// now how we ensure about address of objects ?
          cout << "impossible " << endl;
       else
          cout << "Fine " << endl;//Why isn't the address the same? 

        return 0;
}        

标签: c++ class
4条回答
We Are One
2楼-- · 2019-06-27 10:34

This is largely a repetition of what the other answers have already said, but with a few more references to the ISO C++ standard and some musings about the odd behavior of g++.

The ISO C++11 standard, in section 8.3.4 [dcl.array], paragraph 1, says:

If the constant-expression (5.19) is present, it shall be an integral constant expression and its value shall be greater than zero.

Your class definition:

class Test
{
    int arr[0];
};

violates this rule. Section 1.4 [intro.compliance] applies here:

If a program contains a violation of any diagnosable rule [...], a conforming implementation shall issue at least one diagnostic message.

As I understand it, if a compiler issues this diagnostic and then accepts the program, the program's behavior is undefined. So that's all the standard has to say about your program.

Now it becomes a question about your compiler rather than about the language.

I'm using g++ version 4.7.2, which does permit zero-sized arrays as an extension, but prints the required diagnostic (a warning) if you invoke it with, for example, -std=c++11 -pedantic:

warning: ISO C++ forbids zero-size array ‘arr’ [-pedantic]

(Apparently you're also using g++.)

Experiment shows that g++'s treatment of zero-sized arrays is a bit odd. Here's an example, based on the one in your program:

#include <iostream>

class Empty {
    /* This is valid C++ */
};

class Almost_Empty {
    int arr[0];
};

int main() {
    Almost_Empty arr[2];
    Almost_Empty x, y;

    std::cout << "sizeof (Empty)        = " << sizeof (Empty) << "\n";
    std::cout << "sizeof (Almost_Empty) = " << sizeof (Almost_Empty) << "\n";
    std::cout << "sizeof arr[0]         = " << sizeof arr[0] << '\n';
    std::cout << "sizeof arr            = " << sizeof arr << '\n';

    if (&x == &y) {
        std::cout << "&x == &y\n";
    }
    else {
        std::cout << "&x != &y\n";
    }

    if (&arr[0] == &arr[1]) {
        std::cout << "&arr[0] == &arr[1]\n";
    }
    else {
        std::cout << "&arr[0] != &arr[1]\n";
    }
}

I get the required warning on int arr[0];, and then the following run-time output:

sizeof (Empty)        = 1
sizeof (Almost_Empty) = 0
sizeof arr[0]         = 0
sizeof arr            = 0
&x != &y
&arr[0] == &arr[1]

C++ requires a class, even one with no members, to have a size of at least 1 byte. g++ follows this requirement for class Empty, which has no members. But adding a zero-sized array to a class actually causes the class itself to have a size of 0.

If you declare two objects of type Almost_Empty, they have distinct addresses, which is sensible; the compiler can allocate distinct objects any way it likes.

But for elements in an array, a compiler has less flexibility: an array of N elements must have a size of N times the number of elements.

In this case, since class Almost_Empty has a size of 0, it follows that an array of Almost_Empty elements has a size of 0 *and that all elements of such an array have the same address.

This does not indicate that g++ fails to conform to the C++ standard. It's done its job by printing a diagnostic (even though it's a non-fatal warning); after that, as far as the standard is concerned, it's free to do whatever it likes.

But I would probably argue that it's a bug in g++. Just in terms of common sense, adding an empty array to a class should not make the class smaller.

But there is a rationale for it. As DyP points out in a comment, the gcc manual (which covers g++) mentions this feature as a C extension which is also available for C++. They are intended primarily to be used as the last member of a structure that's really a header for a variable-length object. This is known as the struct hack. It's replaced in C99 by flexible array members, and in C++ by container classes.

My advice: Avoid all this confusion by not defining zero-length arrays. If you really need sequences of elements that can be empty, use one of the C++ standard container classes such as std::vector or std::array.

查看更多
Juvenile、少年°
3楼-- · 2019-06-27 10:43

The standard says that having an array of zero size causes undefined behavior. When you trigger undefined behavior, other guarantees that the standard provides, such as requiring that objects be located at a different address, may not hold.

Don't create arrays of zero size, and you shouldn't have this problem.

查看更多
ら.Afraid
4楼-- · 2019-06-27 10:49

Your class definition is illegal. C++ does not allow array declarations with size 0 in any context. But even if you make your class definition completely empty, the sizeof is still required to evaluate to a non-zero value.

9/4 Complete objects and member subobjects of class type shall have nonzero size.

In other words, if your compiler accepts the class definition and evaluates the above sizeof to zero, that compiler is going outside of scope of standard C++ language. It must be a compiler extension that has no relation to standard C++.

So, the only answer to the "why" question in this case is: because that's the way it is implemented in your compiler.

I don't see what it all has to do with ensuring that different objects have different addresses. The compiler can easily enforce this regardless of whether object size is zero or not.

查看更多
Melony?
5楼-- · 2019-06-27 10:49
  • There is a difference between variable declaration and variable initialization. In your case, you just declare variables; A and B. Once you have declared a variable, you need to initialize it using either NEW or MALLOC.
  • The initialization will now allocate memory to the variables that you just declared. You can initialize the variable to an arbitrary size or block of memory.
  • A and B are both variables meaning you have created two variables A and B. The compiler will identify this variable as unique variables, it will then allocate A to a memory address say 2000 and then allocate B to another memory address say 150.
  • If you want A to point to B or B to point to A, you can make a reference to A or B such as; A = &B. Now A as a memory reference or address to B or rather A points to B. This is called passing variables, in C++ you can either pass variables by reference or pass variables by value.
查看更多
登录 后发表回答