我试图了解如何Ensures()在代码中使用.如示例中所示,如果我尝试使用Ensures()如下...
int main(void)
{
int result = 0;
// Some calculation
Ensures(result == 255);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果result变量不等于255,程序将使用以下输出崩溃"terminate called without an active exception".我的问题是如何Ensures()正确使用?
假设以下代码:
#include <iostream>
#include <vector>
#include <string>
int main() {
std::vector<std::string> lines;
lines.push_back("line");
for (const auto& s : lines) {
std::cout << s;
}
}
Run Code Online (Sandbox Code Playgroud)
在for循环的行中,我收到以下警告:
C26493不要使用执行static_cast downcast,const_cast或reinterpret_cast的C样式转换.
有人可以解释这是从哪里来的吗?我使用Visual Studio 2017 Community Edition版本15.2.
我正在浏览CppCoreGuidelines的T.1,并且有以下示例
例1
template<typename T>
// requires Incrementable<T>
T sum1(vector<T>& v, T s)
{
for (auto x : v) s += x;
return s;
}
Run Code Online (Sandbox Code Playgroud)
例2
template<typename T>
// requires Simple_number<T>
T sum2(vector<T>& v, T s)
{
for (auto x : v) s = s + x;
return s;
}
Run Code Online (Sandbox Code Playgroud)
根据上面的指南,这些例子在概念上是不好的,因为它错过了泛化的机会(受限于"可以递增"或"可以添加"的低级概念).
如何表达上述模板才能被称为良好的通用模板?
我习惯于__attribute__((nonnull))在表达不应该为null的指针时使用.
void f(int* ptr __attribute__((nonnull)));
int main(){
int* ptr = new int(1);
f(ptr);
}
void f(int* ptr){/*impl*/}
Run Code Online (Sandbox Code Playgroud)
但是,对于GSL,还有not_null<T*>包装类型.
void function1(gsl :: not_null n);
void f(gsl::not_null<int*> n);
int main(){
int* ptr = new int(1);
f(ptr);
}
void f(gsl::not_null<int*> n){/*impl*/}
Run Code Online (Sandbox Code Playgroud)
假设有语言设施支持GSL版本,我应该总是not_null<T*>代替__attribute__((nonnull))现在使用吗?
我一直认为编译器属性可能有助于优化,但包装器版本可以解析为未归因的指针.
在他的C++核心指南中,Bjarne Stroustrup建议在通过引用传递数组时使用span.为什么不直接传递一个std :: array对象?
C ++核心准则提到跨度,而不是“跨度”。但是-我看到Microsoft的GSL实现中有一个multi_span类
template <
typename ValueType,
std::ptrdiff_t FirstDimension,
std::ptrdiff_t... RestDimensions
>
class multi_span { ... };
Run Code Online (Sandbox Code Playgroud)
因此,显然这是的某种多维版本gsl::span。但是那是什么意思呢?为什么我们需要这个多维范围,或者更确切地说-我们什么时候使用它?我似乎找不到任何文档。
在微软实施指南支持库中我看到以下代码:
template<class T>
class not_null {
...
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
constexpr explicit not_null(U&& u) : ptr_(std::forward<U>(u)) {
Expects(ptr_ != nullptr);
}
...
constexpr T get() const {
Ensures(ptr_);
return ptr_;
}
...
T ptr_;
}
Run Code Online (Sandbox Code Playgroud)
所有gsl::not_null可能采用指针的构造函数都会检查这些指针是否为空,但我们仍然在每次ptr_取消引用时检查指针 ( ) 的存储值是否为空。鉴于在 C++ 中我们通常不会为不需要的东西付费,为什么我们要进行此检查?
UP:确保按如下方式实现(使用默认标志):
#define GSL_LIKELY(x) (!!(x))
...
#define GSL_CONTRACT_CHECK(type, cond) \
(GSL_LIKELY(cond) ? static_cast<void>(0) : gsl::details::terminate())
...
#define Ensures(cond) GSL_CONTRACT_CHECK("Postcondition", cond)
Run Code Online (Sandbox Code Playgroud) 我试图在Microsoft Visual Studio中创建一些示例代码
int main()
{
const size_t size = 10;
int arr[size];
for (size_t i = 0; i < size; ++i)
arr[i] = i;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
现在JetBrains ResharperC++发出以下警告 arr[i] = i;
我无法理解这意味着什么以及如何解决此警告.
由于这是我经常使用的方案,我有点担心警告.
任何人都可以建议或指出我正确的方向吗?
编辑:将循环更改为:
for (size_t i = 0; i < size; ++i)
arr[i] = 0;
Run Code Online (Sandbox Code Playgroud)
仍然会发出警告.
在C ++核心原则有一个narrow抛出如果转换改变了值施放。查看该库的microsoft实现:
// narrow() : a checked version of narrow_cast() that throws if the cast changed the value
template <class T, class U>
T narrow(U u) noexcept(false)
{
T t = narrow_cast<T>(u);
if (static_cast<U>(t) != u)
gsl::details::throw_exception(narrowing_error());
if (!details::is_same_signedness<T, U>::value && ((t < T{}) != (u < U{}))) // <-- ???
gsl::details::throw_exception(narrowing_error());
return t;
}
Run Code Online (Sandbox Code Playgroud)
我不明白第二个if。它会检查什么特殊情况static_cast<U>(t) != u?为什么还不够?
为了完整性:
narrow_cast只是一个static_cast:
// narrow_cast(): a searchable way to do …Run Code Online (Sandbox Code Playgroud) C.45:不要定义仅初始化数据成员的默认构造函数;改用类内成员初始化器
给出的理由是
原因
使用类内成员初始化器可使编译器为您生成函数。编译器生成的函数可以更有效。
请注意,这是专门针对默认构造函数的,该默认构造函数除了初始化成员外不执行任何操作,并且该准则建议不要编写这样的构造函数。
“坏”的例子是:
Run Code Online (Sandbox Code Playgroud)Example, bad class X1 { // BAD: doesn't use member initializers string s; int i; public: X1() :s{"default"}, i{1} { } // ... };
在该特定示例(或任何其他示例)中,编译器生成的构造函数比用户提供的构造函数更有效率吗?
我天真地希望初始化程序列表提供与类初始化程序相同的优化机会。