Is this a safe workaround? I want to use vector bool but need to pass a pointer to old code expecting C-style array.
typedef std::basic_string<bool> vector_bool;
int main()
{
vector_bool ab;
ab.push_back(true);
ab.push_back(true);
ab.push_back(true);
ab.push_back(false);
bool *b = &ab[0];
b[1] = false;
}
Edit:
Thanks for suggestions of other solutions, but I would really like a definite answer on my above solution. Thanks.
I'm not sure about std::basic_string<bool> because that will instantiate std::char_traits<bool> and I'm not sure if the standard requires that to be defined, or if the char_traits primary template can be left undefined, with only explicit specializations such as char_traits<char> being defined. You're not allowed to provide your own specialization of char_traits<bool> because you can only specialize standard templates if the specialization depends on a user-defined type, which bool obviously isn't. That said, it might work if your stdlib does have a default char_traits definition, and you don't try to use an string operations that require members of char_traits to do anything useful.
Alternatively, this is hacky but might work:
struct boolish { bool value; };
inline boolish make_boolish(bool b) { boolish bish = { b }; return bish; }
std::vector<boolish> b;
b.push_back( make_boolish(true) );
bool* ptr = &b.front().value;
boolish is a trivial type, so as long as an array of boolish has the same representation as an array of bool (which you'd need to check for your compiler, I used a static_assert to check there is no padding) then you might get away with it, although it probably violates the aliasing rules because *ptr and *++ptr are not part of the same array, so incrementing the pointer doesn't point to the next boolish::value it points "past the end" of the previous one (even if those two locations actually have the same address, although [basic.compound]/3 does seem to say that ++ptr does "point to" the next bool).
The syntax gets a bit easier with C++11, you don't need make_boolish ...
#include <vector>
#include <assert.h>
struct boolish { bool value; };
int main()
{
std::vector<boolish> vec(10);
vec.push_back( boolish{true} );
bool* ptr = &vec.front().value;
assert( ptr[10] == true );
ptr[3] = true;
assert( vec[3].value == true );
static_assert( sizeof(boolish) == sizeof(bool), "" );
boolish test[10];
static_assert( sizeof(test) == (sizeof(bool)*10), "" );
}
From "Working Draft C++, 2012-11-02"
21.1 General [strings.general]
1 This Clause describes components for manipulating sequences of any non-array POD (3.9) type.
21.4.1 basic_string general requirements [string.require]
5 The char-like objects in a basic_string object shall be stored contiguously. That is, for any basic_string
object s, the identity &*(s.begin() + n) == &*s.begin() + n shall hold for all values of n such that 0
<= n < s.size().
but
6 References, pointers, and iterators referring to the elements of a basic_string sequence may be invalidated by the following uses of that basic_string object:
— as an argument to any standard library function taking a reference to non-const basic_string as an argument.233
— Calling non-const member functions, except operator[], at, front, back, begin, rbegin, end, and rend.
So, you should be safe as long as you pay attention, not to call these functions, while you use the raw array somewhere else.
Update:
Character traits and requirements are described in 21.2 Character traits [char.traits] and 21.2.1 Character traits requirements [char.traits.require]. Additionally, typedefs and specializations are described in 21.2.2 traits typedefs [char.traits.typedefs] and 21.2.3 char_traits specializations [char.traits.specializations] respectively.
These traits are used in the Input/output library as well. So there are requirements, like eof() or pos_type and off_type, which don't make sense in the context of basic_string.
I don't see any requirement for these traits to be actually defined by an implementatin, besides the four specializations for char, char16_t, char32_t and wchar_t.
Although, it worked out of the box with gcc 4.7 with your example, I defined a minimal bool_traits with just
struct bool_traits {
typedef bool char_type;
static void assign(char_type &r, char_type d);
static char_type *copy(char_type *s, const char_type *p, std::size_t n);
static char_type *move(char_type *s, const char_type *p, std::size_t n);
};
took the default implementation provided (gcc 4.7), and used that like
std::basic_string<bool, bool_traits> ab;
Your environment might already provide a working implementation. If not, you can implement a simple bool_traits or a template specialization std::char_traits<bool> yourself.
You can see the complete interface for character traits in the Working Draft, PDF or at cppreference.com - std::char_traits.
You can also use boost::container::vector. It is exactly like std::vector but it's not specialized for bool.
Related
Intuitively to check whecker pointer p lies in [a,b) one will do
a<=p && p<b
However, comparing pointers from two arrays results in unspecified behavior and thus we cannot safely say p is in [a,b) from this comparison.
Is there any way one can check for this with certainty?
(It would be better if it can be done for std::vector<T>::const_iterator, but I don't think it's feasible.)
Here's a partial solution. You can leverage the fact that the comparison would invoke unspecified behavior, and the fact that a core-constant-expression can't perform this operation:
template<typename T>
constexpr bool check(T *p, T *a, T *b)
{
return a <= p and p < b;
}
Now this function can be used like this:
int main()
{
int arr[5];
int arr_2[5];
constexpr bool b1 = check(arr + 1, arr, arr + 3); // ok
constexpr bool b2 = check(arr_2 + 1, arr, arr + 3); // error
}
Here's a demo.
This obviously works only if the pointer values are known at compile time. At run-time, there is no efficient way of doing this check.
The solution for pointers is to use the comparison objects defined in <functional>, like less/less_equal, etc.
From §20.8.5/8 of the c++17 standard1:
For templates greater, less, greater_equal, and less_equal, the specializations for any pointer type yield a total order, even if the built-in operators <, >, <=, >= do not.
So the solution for pointers would be:
template<typename T>
bool check(T *p, T *a, T *b)
{
return std::less_equal<T*>{}(a,p) && std::less<T*>{}(p,b);
}
Here's a working example using pointers.
There is no such strict guarantee for iterators; however this can be worked around in c++20, since it provides std::to_address which can convert pointable objects to pointers. Note, however, that the behavior of doing this for the purpose of comparisons is only really well defined for contiguous iterators.
Since we know that std::vector iterators cover a contiguous range, we can use this to retrieve the underlying pointer (note: not dereference it, as this would be undefined behavior for the past-the-end pointer).
So for a std::vector<T>::iterator, a solution might look like:
template <typename T>
bool check(const std::vector<T>::const_iterator p, std;:vector<T>::const_iterator a, std::vector<T>::const_iterator b)
{
// Delegate to the pointer check version defined above, for brevity
return check(std::to_address(p), std::to_address(a), std::to_address(b));
}
Here's a working example using iterators.
1 This same note exists all the way back to c++11 under §23.14.7/2, with similar wording.
If I understand you correctly, you want to check if vector iterator is between two other vector iterators.
Then you may use std::distance to compute distance between vector.begin and a, p and b and then simply compare itegers you get from distance return value.
std::distance(first, last) from C++17 can be used for both, but result is undefined if last is unreachable from first (e.g. different range or invalid iterator)
I tried to study libstdc++ source code (GCC 7.2) recently and was confused. Probably I have missed something important, but I started to think that it is impossible to implement basic_string class that will fully comply C++ standard.
Here is a problem that I have faced.
basic_string should be able to accept custom allocator class as template parameter.
allocate method is required as a part of allocator.
allocate is allowed to return objects of user-defined type that "acts like pointer to allocated data". Let's call it my_pointer.
my_pointer should satisfy only the requirements for NullablePointer and RandomAccessIterator. All other requirements are optional. According to standard we may be unable to cast my_pointer to CharT* type (another basic_string template parameter) because it is optional.
On the other hand const CharT* c_str() method should be implemented as a part of the standard, so we have to know how to make this cast.
Items 4 and 5 are conflicting and I don't know how to resolve it.
Hope that you can help me to figure it out.
Thank you!
There are several requirements from the standard that together always ensure the conversion is possible, at least indirectly
Given basic_string<charT, traits, Allocator>, the standard requires charT and allocator_traits<Allocator>::value_type be equal.
allocator_traits<Allocator>::pointer is required to be either Allocator::pointer or Allocator::value_type*.
In the former case, given a Allocator::pointer p, *p is required to be Allocator::value_type&.
In the latter case, everything is trivial.
Allocator::pointer is required to be a contiguous iterator, which requires, given a contiguous iterator q, *(q + n) == *(addressof(*q) + n)
Given an Allocator a, a.allocate(n) is required to return a Allocator::pointer.
Combining everything together, it means this is always correct
template<typename charT, typename traits = /* ... */, typename Allocator = /* ... */>
class basic_string
{
typename std::allocator_traits<Allocator>::pointer _data;
// ...
public:
charT* c_str() { return std::addressof(*_data); }
// ...
};
Where _data possibly stores the result from a previous call to Allocator::allocate
Given the following code:
#include <set>
struct X {
int a, b;
friend bool operator<(X const& lhs, X const& rhs) {
return lhs.a < rhs.a;
}
};
int main() {
std::set<X> xs;
// some insertion...
auto it = xs.find({0, 0}); // assume it != xs.end()
const_cast<X&>(*it).b = 4; // (1)
}
Is (1) defined behavior? I.e., am I allowed to const_cast a reference to an element obtain from a const_iterator of a std::set and modify it if the modification does not alter the ordering?
I have read some posts here and there proposing this kind of const_cast, but I was wondering if this was actually defined behavior.
Whether this has defined behaviour is unclear, but I believe it does.
There appears to be no specific prohibition in the description of std::set on modifying the values, other than the restriction you already hinted at that the comparer must return the same result when passed the same inputs ([associative.reqmts]p3).
However, the general rule on modifying objects defined as const does apply. Whether set defines its elements as const is not spelt out. If it does, then modifying the elements is not allowed ([dcl.type.cv]p4).
But [container.requirements.general]p3 reads:
For the components affected by this subclause that declare an allocator_type, objects stored in these components shall be constructed using the allocator_traits<allocator_type>::construct function and
destroyed using the allocator_traits<allocator_type>::destroy function (20.7.8.2).
std::set<T> declares an allocator_type, which defaults to std::allocator<T>. std::allocator_traits<allocator_type>::construct passes it a T *, causing a T to be constructed, not a const T.
I believe this means std::set<T> is not permitted to define its elements as const, and for lack of any other prohibition, means modifying the elements through const_cast is allowed.
Personally, if I couldn't find any better alternative, I would consider avoiding the issue by putting the whole thing in a wrapper struct, which defines a member mutable X x;. This would allow modifications without const_cast, so long as you take care to avoid changing the relative order of elements already in the set. It would additionally serve as documentation to other readers of your code that the elements of your set can and will be modified.
I would like to add a function that returns the .size() value as an integer, instead of unsigned integer.
Edit: Due to comments, i explain more detailed:
I have code:
int something = 3;
if(arr.size() > something)
Which will produce compiler warning, and i dislike adding (int) to every place where i have this.
So, a solution i thought it would be nice to have sizei() function:
int something = 3;
if(arr.sizei() > something)
Which wouldnt produce a warning.
So, im not wanting to create a separate function, but a function in the std::vector itself.
Edit: Seems like the only way to do this is to create another function, such as:
template <typename T>
inline int sizei(const T &arr){
return (int)arr.size();
}
On the positive side: this doesnt seem to increase my executable size at all.
First of all, why would you want that? I don't see any reason, or advantage:
Anyway, you can do this:
template<typename T>
int size(const std::vector<T> &v) { return (int) v.size(); }
//use
std::vector<int> ints;
//...
int count = size(ints);
Still I don't see any point in doing that. You can simply write:
int count = (int) ints.size();
But I would still say its not better than the following :
size_t count = ints.size(); //don't prefer anything over this. Always use size_t
Advice: avoid using int for size. Prefer size_t.
As for the edit in your question. Why don't you use size_t as:
size_t something = 3;
if(arr.size() > something)
No warning. In my opinion, if you choose the data type consistently throughout your program, you wouldn't come across a situation when you've to compare int with size_t which is defined as unsigned integral type.
Or if there is some legacy code which you've to work with, and which use int for size, then I think its better to use explicit cast when you need it, instead of adding a function in the framework itself, which hides the potential problem:
int something = /*some legacy code API call or something */;
if(arr.size() > (size_t) something)
//or even better;
size_t something = (size_t) /*some legacy code API call or something */;
if(arr.size() > something)
As a rule, in C and C++ you should never use an unsigned type such as size_t to restrict the domain. That's because (1) these languages provide no range checking, and (2) they do provide unreasonable implicit promotions. No range checking means (1) no advantage, and unreasonable implicit promotions means (2) very undesirable disadvantages, so it's plain stupid thing to do: no advantage, very undesirable disadvantages.
However, the standard libraries for these languages do that. They do it for historical reasons only, caught irreversibly in early decisions which at one time made sense. This has both extremely silly consequences such as C99 requiring 17 (!) bits for ptrdiff_t, and it has the aforementioned extremely undesirable consequences such as using inordinately much time on hunting down bugs resulting from implicit promotions (etc.). For example, in C++ you are practically guaranteed that std::string( "bah!" ).length() < -5 – which can easily trip you up and anyway is as silly as it is possible to design.
Now, you can't infuse new member functions in std::vector, but you can add a freestanding function. A good name is countOf. Template it so that it can be applied to just about anything (raw arrays, vectors, etc.).
The triad of functions startOf, endOf and countOf were, as far as I know, first identified by Dietmar Kuehl. C++0x will have std::begin and std::end, but AFAIK no corresponding std::size. In the meantime you can just define this support, which allows you to treat any kinds of container plus raw arrays the same.
An example implementation & further discussion is provided at my blog.
EDIT Adding some code, because it's requested in the comments.
Detection of suitable iterator type:
template< typename Type >
struct It
{
typedef typename Type::iterator T;
};
template< typename Type >
struct It< Type const >
{
typedef typename Type::const_iterator T;
};
template< typename ElemType, Size N >
struct It< ElemType[N] >
{
typedef ElemType* T;
};
And the countOf, startOf and endOf functions, using that deduced iterator type:
template< typename T >
inline Size countOf( T const& c ) { return static_cast<Size>( c.size() ); }
template< typename T, Size N >
inline Size countOf( T (&)[N] ) { return N; }
template< typename T >
inline typename It<T>::T startOf( T& c ) { return c.begin(); }
template< typename T, Size N >
inline T* startOf( T (&a)[N] ) { return a; }
template< typename T >
inline typename It<T>::T endOf( T& c ) { return c.end(); }
template< typename T, Size N >
inline T* endOf( T (&a)[N] ) { return a + N; }
where Size is a typedef for ptrdiff_t.
Note: in 64-bit Windows int (and even long) is 32-bit. Hence, int is in general not sufficient for a really large array. ptrdiff_t is guaranteed to be able to represent the difference between any two pointers, when that difference is well-defined.
Cheers & hth.
You can derive from vector as follows:
template<typename T>
class my_vector : public vector<T>
{
// missing constructors!
int size() const
{
if (vector<T>::size() > INT_MAX)
throw std::range_error("too many elements in vector");
return (int) vector<T>::size();
}
};
The down-side is that you'll have to define and forward constructors yourself.
I would favor using an explicit cast to int instead of a function: static_cast<int> (v.size()). Even better would be to always use size_t when dealing with memory sizes. For example, favor for (size_t i=0; i < v.size(); ++i) over for (int i=0; i < (int) v.size(); ++i). Use the right type for the job. You should not be comparing std::vector sizes with a signed type.
See the following references for why you should prefer size_t to int:
Using size_t appropriately can improve the portability, efficiency, or readability of your code. Maybe even all three.
unsigned int vs. size_t
Is it good practice to use size_t in C++?
When should I use std::size_t?
Quick answer for .size() is: no. For vectors, the possibilities are its storage value and the alloc method (default new/delete, not normally overridden) along with methods that utilize InputIterator.
Most are going to ask why would you want a different size_t. If it's just the annoy warnings, you can cast or use unsigned integers to iterate/check against size(). (If it's a lot of code, you going to have to find/replace)... If it is handling empty conditions, you could wrap the vector in a class with some smarts. As an aside, since I don't know your problem at hand, a good place to look for ideas and already implemented features is std library's algorithms such as sort, for_each, find, and lots more.
For std algorithms, see: http://www.sgi.com/tech/stl/table_of_contents.html
While #Nawaz, in my opinion, provided the most appropriate answer, if you really want to add an additional member to std::vector<> it isn't really possible. #zvrba provided the only way that could be accomplished, but as stated in the comments there the std container types do not have virtual destructors and therefore are not meant to be subclassed from.
However, you could implement a new type of vector using a container adaptor, like this:
template <class T>
class my_vector
{
public:
int size_i() const
{
return static_cast<int>(container_.size());
}
private:
std::vector<T> container_;
};
The drawback here is that you have to explicitly expose the functions of the container that you actually need to support. If you are using 'std::vector' normally throughout your code, this would likely be a significant change. See 'std::queue' for an implementation example of a container adaptor.
I've run into some annoying issues with const-correctness in some templated code, that ultimately boils down to the following observation: for some reason, given an STL-ish Container type T, const typename T::pointer does not actually seem to yeild a constant pointer type, even if T::pointer is equivalent to T::value_type*.
The following example illustrates the problem. Suppose you have a templated function that takes a Container which must meet the STL Random Access Container concept requirements.
template <class Container>
void example(Container& c)
{
const typename Container::pointer p1 = &c[0]; // Error if c is const
const typename Container::value_type* p2 = &c[0];
}
Then, if we pass this function a const container...
const std::vector<int> vec(10);
example(vec);
...we get an invalid conversion from const int* to int*. But why is const typename Container::pointer not the same as const int* in this example?
Note that if I change const typename Container::pointer to simply typename Container::const_pointer it compiles fine, however, as far as I can tell, the const_pointer typedef is an extension, (I don't see it mentioned in the C++ standard Container Requirements (23.5, Table 65)), and so therefore I don't want to use it.
So how can I obtain a generic, const-correct pointer type from a container T? (I really can't see how to do this without using boost::mpl::if_ along with type_traits to check if the container is constant...but there must be a less verbose way to do this)
Edit: In case it matters, I'm using gcc 4.3.2 to compile this.
It doesn't work because your const does not apply to what you think it applies to. For example, if you have
typedef int* IntPtr;
then
const IntPtr p;
does not stand for
const int* p;
but rather stands for
int* const p;
Typedef-name is not a macro. Once the "pointerness" of the type is wrapped into a typedef-name, there's no way to use it to create a pointer-to-const type anymore. I.e. there's absolutely no way to use the above IntPtr typedef-name to produce an equivalent of
const int* p;
You have to either use to pointee type explicitly (as you did with value_type), or check whether your container defines a different typedef-name, with const already wrapped "inside" (like const_pointer or something like that).
This:
typename Container::pointer
Has the type int* (in our case). I don't know the terminology, so sorry for that, but pointers point to a type. That is, Container::pointer is a pointer to a mutable T, and adding const is only going to make this a const pointer (not a pointer to const), because Container::pointer has already been defined to point to a mutable T.
It seems only const_pointer, either from the class or your own:
typedef const typename Container::value_type* const_pointer
Will work.
The allocator requirements (cf. 20.1.5, Table 32, "Allocator requirements") state that allocators for the STL containers shall have an Allocator::const_pointer. All of the STL containers (the eight containers listed in Section 23) define a Container::const_pointer typedef as:
typedef typename Allocator::const_pointer const_pointer;
As you state in your question, however, containers (other than those eight) are not required to have a Container::const_pointer typedef.
This might be of relevance here (from SGI STL reference):
[6] As in the case of references [5], the pointer type must have the same semantics as C++ pointers but need not actually be a C++ pointer. "Smart pointers," however, unlike "smart references", are possible. This is because it is possible for user-defined types to define the dereference operator and the pointer member access operator, operator* and operator->.
It is possible by using a template. The trick is to remove the pointer first, then apply const on the type and finally applying pointer to the type - for instance using std::remove_pointer yields:
typedef const std::remove_pointer<Container::pointer>::type* PointerToConst;