std::unique_ptr
with 的行为custom deleter
基于删除程序的静态类型。没有多态性,没有基于在运行时传递的实际删除程序的运行时行为,因为提供的派生删除程序已被切片为声明的删除程序的静态类型。
(其目的是通过这种方式设计的,以允许带有
default deleter
或带有的unique_ptr的custom deleter without any data members
大小与原始指针的大小相同)。
unique_ptr
with的静态行为custom deleter
:class A {};
struct BaseDeleter {
virtual void operator()(A* p) const {
std::cout << "in BaseDeleter" << std::endl;
delete p;
}
};
struct DerivedDeleter: BaseDeleter {
void operator()(A* p) const override {
std::cout << "in DerivedDeleter" << std::endl;
delete p;
}
};
int main() {
auto unique_var = std::unique_ptr<A, BaseDeleter>(new A);
unique_var = std::unique_ptr<A, DerivedDeleter>(new A); …
Run Code Online (Sandbox Code Playgroud) C++ 规范(例如C++17 [class.static] §2)说:
静态数据成员的定义在其类的范围内。
举个例子(取自C++14 规范):
int g();
struct X {
static int g();
};
struct Y : X {
static int i;
};
int Y::i = g(); // equivalent to Y::g();
Run Code Online (Sandbox Code Playgroud)
规范中的确切措辞和示例多年来发生了变化,由于某些未知原因,C++11和C++14具有与上述非常相似的示例,C++17和C++20更喜欢初始化示例来自静态数据成员。在C ++ 20措辞也更准确。但似乎这条规则并没有实际的变化。
似乎这条规则不适用于模板化类的继承:
template<int VALUE>
struct base {
static int foo() { return VALUE; }
static constexpr int z = -1;
};
template<int VALUE>
struct foobar: base<VALUE> {
static int …
Run Code Online (Sandbox Code Playgroud) 我几乎可以肯定,如果没有反思,我正在寻找的东西就无法完成,而反思还没有出现在语言中。但有时我会对 SO 中的特殊答案感到惊讶,所以让我们尝试一下。
\n是否可以推导出具有共同共享基类的两种类型的“common_base”,因此以下内容是可能的(伪代码! -语言中没有 ,这就是我想要实现的魔力) :common_base_t
template<typename T1, typename T2>\nconst common_base_t<T1, T2>& foo(const T1& a1, const T2& a2) {\n if(a1 < a2) return a1;\n return a2;\n}\n
Run Code Online (Sandbox Code Playgroud)\n请注意,上面a1
的 和a2
并不共享 a common_type
,只是作为兄弟(共享相同的基数),因此我们不能使用三元运算符。
另请注意,将上述返回类型更改为 并const auto&
不能解决问题(它不会编译:auto return type 的推导不一致)。
这是 na\xc3\xafve 实现,要求调用者声明预期的返回类型:
\ntemplate<typename R>\nconst R& foo(const auto& a1, const auto& a2) {\n if(a1 < a2) return a1;\n return a2;\n}\n
Run Code Online (Sandbox Code Playgroud)\n然后我们可以这样调用它: …
通常我更喜欢unique_ptr
从工厂回来。unique_ptr
最近我遇到了为继承的类返回 a 的问题enable_shared_from_this
。此类的用户可能会意外地调用shared_from_this()
,尽管它不属于任何shared_ptr
,这会导致std::bad_weak_ptr
异常(或在 C++17 之前未定义的行为,通常作为异常实现)。
代码的简单版本:
class Foo: public enable_shared_from_this<Foo> {
string name;
Foo(const string& _name) : name(_name) {}
public:
static unique_ptr<Foo> create(const string& name) {
return std::unique_ptr<Foo>(new Foo(name));
}
shared_ptr<Foo> get_shared() {return shared_from_this();}
void doIt()const {cout << "Foo::doIt() <" << name << '>' << endl;}
virtual ~Foo() {cout << "~Foo() <" << name << '>' << endl;}
};
int main() {
// ok behavior
auto pb1 = …
Run Code Online (Sandbox Code Playgroud) 给出以下代码:
class A;
struct B {
static void doIt(A* pa);
};
struct C {
static void doIt(A* pa);
};
class A {
int i = 9;
// below works but requires a line per each type
friend void B::doIt(A* pa);
friend void C::doIt(A* pa);
// the below however doesn't work
// template<typename T>
// friend void T::doIt(A* pa);
// (gcc error: member 'void T::doIt(A*)' declared as friend before type 'T' defined)
// (clang just ignores the above and the error …
Run Code Online (Sandbox Code Playgroud) 很明显,std :: initializer_list不是一个实际的容器.该标准明确定义了使用std :: initializer_list可以做什么和不能做什么.
但是为什么语言会保留做愚蠢事情的选择,比如将一个临时的std :: initializer_list分配给另一个 - 当它可以在std :: initializer_list的移动赋值运算符上用= delete时很容易被阻塞?
这是一个破解的代码示例,它编译:
void foo(std::initializer_list<int> v) {
std::cout << *v.begin() << std::endl;
}
int main() {
int a = 1, b = 2, c = 3;
auto val = {a, b, c}; // ok, extending the lifetime of {a, b, c}
foo(val); // prints ok
int i = 7;
val = {i}; // doesn't handle well assignment of temporary
foo(val); // prints garbage...
}
Run Code Online (Sandbox Code Playgroud)
输出,由@nwp提供: …
以下代码与clang(x86_64-pc-linux-gnu 上的版本 5.0.0-3~16.04.1)和gcc (9.2.0) 的行为不同。
void operator delete(void* ptr) noexcept {
std::cout << "overloaded delete" << std::endl;
free(ptr);
}
int main() {
int* pint = new int;
delete pint; // clang doesn't go through overloaded operator delete, gcc does
}
Run Code Online (Sandbox Code Playgroud)
gcc通过重载,operator delete
而clang避免它更喜欢global delete
.
(当添加重载时,operator new
两个编译器都同意并通过两个重载版本)。
C++20 增加了可寻址函数 规则16.5.4.2.1 [namespace.std]/6 : -- 重点是我的 --
让F表示标准库函数([global.functions])、标准库静态成员函数或标准库函数模板的实例化。除非F被指定为 可寻址函数,否则C++ 程序的行为是未指定的(可能格式错误),如果它显式或隐式地尝试形成指向 F 的指针。 [注意:形成此类指针的可能方法包括应用一元 &运算符 ([expr.unary.op])、addressof ([specialized.addressof]) 或函数到指针的标准转换 ([conv.func])。— 尾注 ] 此外,如果 C++ 程序试图形成对 F 的引用,或者如果它试图形成一个指向成员的指针来指定标准库非静态成员函数([member .functions]) 或标准库成员函数模板的实例化。
据我所知,数学函数没有被规范标记为可寻址函数。
这是否意味着以下代码自 C++20 以来是非法的(如cppreference和其他标准库函数的示例所指出的):
// unspecified and illegal?
auto func = static_cast<float (*)(float, float)>(std::pow);
std::cout << func(2, 4) << std::endl;
Run Code Online (Sandbox Code Playgroud)
下面的代码呢,它合法吗?
// legal? or unspecified and illegal?
std::function<float(float, float)> f = static_cast<float(*)(float, float)>(std::pow);
std::cout …
Run Code Online (Sandbox Code Playgroud) template<typename T>
class number {
T num;
public:
number(T num = 0): num(num) {}
friend auto add(auto a, auto b);
};
auto add(auto a, auto b) {
// the decltype(a) is needed to make clang happy
// see: /sf/ask/4394546971/
return number<decltype(a)>{a}.num + number<decltype(b)>{b}.num;
}
int main() {
auto result = add(1.0, 2.0);
}
Run Code Online (Sandbox Code Playgroud)
gcc 提供的编译错误(版本 10.1 with -std=c++20):
In instantiation of 'auto add(auto:13, auto:14) [with auto:13 = double; auto:14 = double]':
error: 'double …
Run Code Online (Sandbox Code Playgroud) C++20 弃用了类型上的某些特定操作volatile
(遵循P1152)。
以下代码在 C++20 之前有效:
void busyLoop(std::size_t count) {
for (volatile size_t counter = 0; counter < count; ++counter);
}
Run Code Online (Sandbox Code Playgroud)
现在生成弃用警告:
warning: '++' expression of 'volatile'-qualified type is deprecated [-Wvolatile]
Run Code Online (Sandbox Code Playgroud)
更改++
to+=
或 tocounter = counter + 1
没有帮助,因为问题似乎在于基于易失性类型计算新值。
上面的代码如何调整以适应新的C++20规则?
c++ ×9
c++20 ×3
c++11 ×2
gcc ×2
templates ×2
unique-ptr ×2
auto ×1
clang ×1
definition ×1
deprecated ×1
friend ×1
scope ×1
shared-ptr ×1
static ×1
type-traits ×1
volatile ×1