|
|||
|
The C++11 spec says at 1.8p5
"Unless it is a bit-field (9.6), a most derived object shall have a non-zero size and shall occupy one or more bytes of storage. Base class subobjects may have zero size." The following is supposed to be valid int *x = new int[0]; The object created by "new int[0]" has zero size (int[0] == 0 * sizeof(int)), but that contradicts the above quote. How is this to be interpreted? -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|
||||
|
||||
|
|
|
|||
|
On 03.05.2012 23:25, Johannes Schaub wrote:
> The C++11 spec says at 1.8p5 > > "Unless it is a bit-field (9.6), a most derived object shall have a > non-zero size and shall occupy one or more bytes of storage. Base class > subobjects may have zero size." > > The following is supposed to be valid > > int *x = new int[0]; > Well, no, it's not valid. §5.3.4/6 "Every constant-expression in a noptr-new-declarator shall be an integral constant expression (5.19) and evaluate to a strictly positive value" However, int size = 0; int* x = new int[size]; is valid, and for the purpose of discussing the essence of your question, amounts to the same. > The object created by "new int[0]" has zero size (int[0] == 0 * > sizeof(int)), but that contradicts the above quote. > > How is this to be interpreted? The returned pointer is not a pointer to an object. It is just a unique pointer value. §5.3.4/7 "When the value of the expression in a noptr-new-declarator is zero, the allocation function is called to allocate an array with no elements." Then about the allocation function, "If the request succeeds, the value returned shall be a non-null pointer value (4.10) p0 different from any previously returned value p1, unless that value p1 was subsequently passed to an operator delete. The effect of dereferencing a pointer returned as a request for zero size is undefined" Cheers & hth., - Alf -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
On 2012-05-03 16:30, Alf P. Steinbach wrote:
> On 03.05.2012 23:25, Johannes Schaub wrote: >> The C++11 spec says at 1.8p5 >> >> "Unless it is a bit-field (9.6), a most derived object shall have a >> non-zero size and shall occupy one or more bytes of storage. Base class >> subobjects may have zero size." >> >> The following is supposed to be valid >> >> int *x = new int[0]; >> > > Well, no, it's not valid. > > §5.3.4/6 > "Every constant-expression in a noptr-new-declarator shall be an > integral constant expression (5.19) and evaluate to a strictly > positive value" Yes, it's valid. In the above sentence, a "constant-expression in a noptr-new-declarator" means not a constant expression in general, but what appears in the following grammar: noptr-new-declarator: [ expression ] attribute-specifier-seq_opt noptr-new-declarator [ constant-expression ] attribute-specifier-seq_opt where "expression" means the first dimension and "constant-expression" everything else. Therefore, the above sentence only restricts the size of all dimensions but the first. The size of the first dimension is governed by the next paragraph, §5.3.4/7, which you quoted. > >> The object created by "new int[0]" has zero size (int[0] == 0 * >> sizeof(int)), but that contradicts the above quote. >> >> How is this to be interpreted? > > The returned pointer is not a pointer to an object. > > It is just a unique pointer value. Then, what kind of pointer is it? A pointer may be an object pointer, a function pointer, a pointer to member (either data or function). I think it is a pointer to an object of a unspecified positive size that you just cannot dereference into (without UB, of course). §3.7.4.1/2: "The pointer returned shall be suitably aligned so that it can be converted to a pointer of any complete object type with a fundamental alignment requirement and then used to access the object or array in the storage allocated [...])." This specifies that the returned pointer can be converted to a pointer of any (complete) object type. In addition, the block of storage allocated is allowed to be larger than the requested size, so there's no problem in the allocated object being a non-zero size. -- Seungbeom Kim [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
On May 3, 6:30 pm, "Alf P. Steinbach" <alf.p.steinbach
+use...@gmail.com> wrote: > > The object created by "new int[0]" has zero size (int[0] == 0 * > > sizeof(int)), but that contradicts the above quote. > > > How is this to be interpreted? > > The returned pointer is not a pointer to an object. > > It is just a unique pointer value. I don't think that is a valid summary. Allocating an array of size zero returns a pointer to a memory object representing an array with zero elements. It will leak if not deleted. Dereferencing it has undefined behavior--just like going out of bounds on any other sized array. It really uses space in memory so that it has an actual unique address. If you iterated this array, your begin/end iterators would both be referring to the same location, designating an empty range. chris -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
Am 04.05.2012 02:46, schrieb Seungbeom Kim:
>>> The object created by "new int[0]" has zero size (int[0] == 0 * >>> sizeof(int)), but that contradicts the above quote. >>> >>> How is this to be interpreted? >> >> The returned pointer is not a pointer to an object. >> >> It is just a unique pointer value. > > Then, what kind of pointer is it? A pointer may be an object pointer, > a function pointer, a pointer to member (either data or function). > > I think it is a pointer to an object of a unspecified positive size > that you just cannot dereference into (without UB, of course). > I think you have a point. I think the only way we could observe the size is by "sizeof", but which cannot be applied here. But on the other hand, the same is true for empty base class subobjects, but which are mentioned explicitly by clause 1. However, the spec also says about the argument of "operator new": "That argument shall be no less than the size of the object being created; it may be greater than the size of the object being created only if the object is an array.". At other places it says that "operator new" may be calld with a size parameter of 0. That implies that the size of the array object created by "new int[0]" *can* be 0 on an implementation, I think. Related to that: What *is* definite is that the array has zero elements. That contradicts 8.3.4p1. That paragraph talks not only about declarators in a declaration like "T d[N];" - it also talks about the types themselfs (and hence this paragraph is linked to by 3.9p2). It says "An object of array type contains a contiguously allocated non-empty set of N subobjects of type T." That's a plain contradiction to clause 5.3.4. If it said the following it would be fine "An object of D's type contains a contiguously allocated non-empty set of N subobjects of type T.". It goes hand in hand with footnote 105 which is likewise in error: "The syntax provides for empty initializer-lists, but nonetheless C++ does not have zero length arrays.". I think that 8.3.4 should ideally elaborate the description of array types by just describing and constraining the way it may denote them (by type-ids). The new-type-ids will then naturally extend array types to exist even with zero length, because new-type-ids allow to denote those types in addition. I think that's a natural way to describe the type entity kind: Just describe and constraint their specifiers, and let them imply what kind of types exist. 8.3.4 goes beyond that and tries to step into describing and constraining the type entity itself, which in this case goes horribly wrong. (I'm aware of http://herbsutter.com/2009/09/02/whe...th-array-okay/, but I'm not convinced). -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
On Thursday, May 3, 2012 4:25:04 PM UTC-5, Johannes Schaub (litb) wrote:
> The C++11 spec says at 1.8p5 > > "Unless it is a bit-field (9.6), a most derived object shall have a > non-zero size and shall occupy one or more bytes of storage. Base class > subobjects may have zero size." > > The following is supposed to be valid > > int *x = new int[0]; > > The object created by "new int[0]" has zero size (int[0] == 0 * > sizeof(int)), but that contradicts the above quote. > > How is this to be interpreted? There is no contradiction if sizeof(*new int[0]) != 0, which is true at least for GCC 4.6.3. 5.3.3/2 (sizeof) says that "When applied to an array, the the result is the total number of bytes in the array. This implies that the size of an array of n elements is n times the size of an element". It's not clear to me if "This implies" is meant to define a hard requirement, but in any case if the intention of the standard is that arrays of zero elements have non-zero size it would be nice to say so explicitly. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
On 05.05.2012 00:15, cartec69@gmail.com wrote:
> On Thursday, May 3, 2012 4:25:04 PM UTC-5, Johannes Schaub (litb) wrote: >> The C++11 spec says at 1.8p5 >> >> "Unless it is a bit-field (9.6), a most derived object shall have a >> non-zero size and shall occupy one or more bytes of storage. Base class >> subobjects may have zero size." >> >> The following is supposed to be valid >> >> int *x = new int[0]; >> >> The object created by "new int[0]" has zero size (int[0] == 0 * >> sizeof(int)), but that contradicts the above quote. >> >> How is this to be interpreted? > > There is no contradiction if sizeof(*new int[0]) != 0, which is true > at least for GCC 4.6.3. 5.3.3/2 (sizeof) says that "When applied to > an array, the the result is the total number of bytes in the array. This > implies that the size of an array of n elements is n times the size of an > element". It's not clear to me if "This implies" is meant to define a hard > requirement, but in any case if the intention of the standard is that > arrays of zero elements have non-zero size it would be nice to say so > explicitly. That does not apply sizeof to an array type object. Cheers & hth., - Alf -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
On 04.05.2012 22:06, Chris Uzdavinis wrote:
> On May 3, 6:30 pm, "Alf P. Steinbach"<alf.p.steinbach > +use...@gmail.com> wrote: > >>> The object created by "new int[0]" has zero size (int[0] == 0 * >>> sizeof(int)), but that contradicts the above quote. >> >>> How is this to be interpreted? >> >> The returned pointer is not a pointer to an object. >> >> It is just a unique pointer value. > > I don't think that is a valid summary. Allocating an array of size > zero returns a pointer to a memory object representing an array with > zero elements. No, it can't be an "object" in the standard's sense of "object". As Johannes noted in the original posting, such an object would have zero size, which by §1.8/5 is forbidden for a most derived object, unless that object is a bit field. So, your POV is not a valid way to look at it. All that we know about the result is that by §5.3.4/7, which I quoted earlier, it is a (dynamically) unique pointer value. It is IMHO needless complication to add more interpretation that is neither specified nor strongly implied by the standard, at least when that interpretation does not confer great explanatory power, and Mr. Occam, with his sharpish razor blade in plain sight, therefore says "no, don't do that, no No NO!". E.g., you don't need to assert a non-zero sized region of memory, because the uniqueness requires a non-zero size region of memory reserved for that pointer, which implies that... > It will leak if not deleted. Yep. > Dereferencing it has > undefined behavior--just like going out of bounds on any other sized > array. It really uses space in memory so that it has an actual unique > address. If you iterated this array, your begin/end iterators would > both be referring to the same location, designating an empty > range. Yes. Cheers & hth., - Alf -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
On 2012-05-04 15:15, cartec69@gmail.com wrote:
> > There is no contradiction if sizeof(*new int[0]) != 0, [...] 'new int[n]' "yields a pointer to the initial element (if any) of the array" (5.3.4/5), not a pointer to the entire array, so '*new int[n]' just designates an int object, and sizeof(*new int[n]) is always sizeof(int). There's no way to apply sizeof to a dynamically allocated array object. It is interesting that 5.3.4/5 writes "(if any)", as if it took zero-length arrays into account, and a footnote in 5.3.5 even says "Zero-length arrays do not have a first element," though another footnote in 8.5.1 says "C++ does not have zero length arrays." Is the standard contracting itself? -- Seungbeom Kim [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
On May 3, 2:25 pm, Johannes Schaub <schaub.johan...@googlemail.com>
wrote: > The C++11 spec says at 1.8p5 > > "Unless it is a bit-field (9.6), a most derived object shall have a > non-zero size and shall occupy one or more bytes of storage. Base > class subobjects may have zero size." > > The following is supposed to be valid > > int *x = new int[0]; > > The object created by "new int[0]" has zero size (int[0] == 0 * > sizeof(int)), but that contradicts the above quote. > > How is this to be interpreted? In my view the word "array" is overloaded in the standard, the rules are different for statically and dynamically allocated arrays though both are just called arrays. One meaning of the "array" is an object defined in the form of "T array[n1][n2]...", to which the non-negative compile-time const requirements are applied as well as sizeof(array) is defined as n*sizeof(T) in 5.3.3/2. A different meaning of the "array" is an object which is the result of an array form of new expression calling "operator new[]", which isn't actually the type of an array, for creation of which the non-negative integral expression is required and "sizeof(*new T[n])" is always positive as described in 5.3.4/7. The trait is_array also treats them differently: #include <type_traits> #include <iostream> int main() { int a[10]; int* b = new int[10]; std::cout << "a is an array: " << std::boolalpha << std::is_array<decltype(a)>::value; std::cout << "\n*b is an array: " << std::boolalpha << std::is_array<decltype(*b)>::value; } The output: a is an array: true *b is an array: false -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
On 05.05.2012 08:39, Gene Bushuyev wrote:
> On May 3, 2:25 pm, Johannes Schaub<schaub.johan...@googlemail.com> > wrote: >> The C++11 spec says at 1.8p5 >> >> "Unless it is a bit-field (9.6), a most derived object shall have a >> non-zero size and shall occupy one or more bytes of storage. Base >> class subobjects may have zero size." >> >> The following is supposed to be valid >> >> int *x = new int[0]; >> >> The object created by "new int[0]" has zero size (int[0] == 0 * >> sizeof(int)), but that contradicts the above quote. >> >> How is this to be interpreted? > > In my view the word "array" is overloaded in the standard, the rules > are different for statically and dynamically allocated arrays though > both are just called arrays. One meaning of the "array" is an object > defined in the form of "T array[n1][n2]...", to which the > non-negative compile-time const requirements are applied as well as > sizeof(array) is defined as n*sizeof(T) in 5.3.3/2. A different > meaning of the "array" is an object which is the result of an array > form of new expression calling "operator new[]", which isn't > actually the type of an array, for creation of which the > non-negative integral expression is required and "sizeof(*new T[n])" That does not apply sizeof to an array type object. > is always positive as described in 5.3.4/7. No, it describes no such thing. It would be remarkable it the standard confused pointers and arrays (it's a novice level misconception). > The trait is_array also treats them differently: > > #include<type_traits> > #include<iostream> > > int main() > { > int a[10]; > int* b = new int[10]; > > std::cout<< "a is an array: "<< std::boolalpha<< > std::is_array<decltype(a)>::value; > std::cout<< "\n*b is an array: "<< std::boolalpha<< > std::is_array<decltype(*b)>::value; > } > > The output: > > a is an array: true > *b is an array: false It doesn't tell you anything, because type information is discarded in the conversion to pointer-to-first-element, which is called a "decay" to pointer (note: also function types can decay to pointers). Applying * does not magically retrieve that lost information. The type of the object created is 'int[10]', while the type that you pass to decltype is 'int'. Cheers & hth., - Alf -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
Am 05.05.2012 02:36, schrieb Alf P. Steinbach:
> On 04.05.2012 22:06, Chris Uzdavinis wrote: >> On May 3, 6:30 pm, "Alf P. Steinbach"<alf.p.steinbach >> +use...@gmail.com> wrote: >> >>>> The object created by "new int[0]" has zero size (int[0] == 0 * >>>> sizeof(int)), but that contradicts the above quote. >>> >>>> How is this to be interpreted? >>> >>> The returned pointer is not a pointer to an object. >>> >>> It is just a unique pointer value. >> >> I don't think that is a valid summary. Allocating an array of size >> zero returns a pointer to a memory object representing an array >> with zero elements. > > No, it can't be an "object" in the standard's sense of "object". As > Johannes noted in the original posting, such an object would have > zero size, which by §1.8/5 is forbidden for a most derived object, > unless that object is a bit field. > It says just as clear that "new" attempts to create an object of the new-type-id. And that the type of that object is the allocated type. Is it not a contradiction? -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
Am 05.05.2012 08:39, schrieb Gene Bushuyev:
> On May 3, 2:25 pm, Johannes Schaub<schaub.johan...@googlemail.com> > wrote: >> The C++11 spec says at 1.8p5 >> >> "Unless it is a bit-field (9.6), a most derived object shall have a >> non-zero size and shall occupy one or more bytes of storage. Base >> class subobjects may have zero size." >> >> The following is supposed to be valid >> >> int *x = new int[0]; >> >> The object created by "new int[0]" has zero size (int[0] == 0 * >> sizeof(int)), but that contradicts the above quote. >> >> How is this to be interpreted? > > In my view the word "array" is overloaded in the standard, the rules > are different for statically and dynamically allocated arrays though > both are just called arrays. One meaning of the "array" is an object > defined in the form of "T array[n1][n2]...", to which the > non-negative compile-time const requirements are applied as well as > sizeof(array) is defined as n*sizeof(T) in 5.3.3/2. A different > meaning of the "array" is an object which is the result of an array > form of new expression calling "operator new[]", which isn't > actually the type of an array, for creation of which the > non-negative integral expression is required and "sizeof(*new T[n])" > is always positive as described in 5.3.4/7. > > The trait is_array also treats them differently: > > #include<type_traits> > #include<iostream> > > int main() > { > int a[10]; > int* b = new int[10]; > > std::cout<< "a is an array: "<< std::boolalpha<< > std::is_array<decltype(a)>::value; > std::cout<< "\n*b is an array: "<< std::boolalpha<< > std::is_array<decltype(*b)>::value; > } > > The output: > > a is an array: true > *b is an array: false > > As has ben said, `b` is a pointer and `decltype(*b)` is `int&`. The type of `new T` where `T` is an array type is type erased with respect to the type of the object that `new T` creates, because `T` may depend on runtime values (when `T` has the form `U[n]` where `n` depends on runtime values). You would have to check `decltype(*+a)` in the first case to apply the same thing to both cases, and see that your testcase yields "false" for both cases. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
Am 05.05.2012 08:39, schrieb Gene Bushuyev:
> On May 3, 2:25 pm, Johannes Schaub<schaub.johan...@googlemail.com> > wrote: >> The C++11 spec says at 1.8p5 >> >> "Unless it is a bit-field (9.6), a most derived object shall have a >> non-zero size and shall occupy one or more bytes of storage. Base >> class subobjects may have zero size." >> >> The following is supposed to be valid >> >> int *x = new int[0]; >> >> The object created by "new int[0]" has zero size (int[0] == 0 * >> sizeof(int)), but that contradicts the above quote. >> >> How is this to be interpreted? > > In my view the word "array" is overloaded in the standard, the rules > are different for statically and dynamically allocated arrays though > both are just called arrays. One meaning of the "array" is an object > defined in the form of "T array[n1][n2]...", to which the > non-negative compile-time const requirements are applied as well as > sizeof(array) is defined as n*sizeof(T) in 5.3.3/2. A different > meaning of the "array" is an object which is the result of an array > form of new expression calling "operator new[]", which isn't > actually the type of an array, for creation of which the > non-negative integral expression is required and "sizeof(*new T[n])" > is always positive as described in 5.3.4/7. > Does that mean that the following is undefined behavior, because the pointer is only allowed to point to an object of the type which it compounds? (aliasing-violation, c.f. 3.10/15) int x[3] = {}; int(*p)[3] = &x; p[0][0] = 42; // valid so far int n = 3; p = (int(*)[3])new int[n]; p[0][0] = 42; // undefined behavior? According to you, if I understood you correctly, the object created by the new-expression doesn't have the type "int[3]". What type is it? -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
On 2012-05-04 22:15:14 +0000, Johannes Schaub said:
> > I think you have a point. I think the only way we could observe the size > is by "sizeof", but which cannot be applied here. But on the other hand, > the same is true for empty base class subobjects, but which are > mentioned explicitly by clause 1. Empty base class subobjects can be detected by looking at addresses of bases. -- Pete Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The Standard C++ Library Extensions: a Tutorial and Reference (www.petebecker.com/tr1book) [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|
![]() |
| Thread Tools | |
| Display Modes | |
|
|