似乎普遍认为,大括号初始化应优先于其他形式的初始化,但是由于将C++ 17 扩展引入聚合初始化,似乎存在意外转换的风险.请考虑以下代码:
struct B { int i; };
struct D : B { char j; };
struct E : B { float k; };
void f( const D& d )
{
E e1 = d; // error C2440: 'initializing': cannot convert from 'D' to 'E'
E e2( d ); // error C2440: 'initializing': cannot convert from 'D' to 'E'
E e3{ d }; // OK in C++17 ???
}
struct F
{
F( D d ) …
Run Code Online (Sandbox Code Playgroud) 为什么类D
编译,但类C
没有?
class A
{
public:
A(int) {}
};
template <class T>
class B : private T // Note: private base class
{
public:
using T::T;
};
class C : public B<A>
{
public:
C() : B<A>(123) {} // Error: 'class A A::A' is inaccessible
}; // within this context
using BA = B<A>;
class D : public BA
{
public:
D() : BA(123) {} // OK
};
Run Code Online (Sandbox Code Playgroud)
我用GCC,Clang和Visual C++ 进行了测试,它们都是一样的.改变class B : private …
在下面的代码中,函数f()
可以调用operator bool()
和不完整的operator *()
成员函数.但是当函数试图调用那些相同的成员函数时,编译器突然想要一个完整的类型并尝试实例化,然后失败.由于某种原因,不会导致模板实例化并正确编译,如功能中所示.这是为什么?有什么不同和?unique_ptr<C>
class C
g()
unique_ptr<X<C>>
X<C>
unique_ptr<X<C>>::get()
h()
get()
operator bool()
operator *()
#include <memory>
class C;
std::unique_ptr<C> pC;
C& f() {
if ( !pC ) throw 0; // OK, even though C is incomplete
return *pC; // OK, even though C is incomplete
}
template <class T>
class X
{
T t;
};
std::unique_ptr<X<C>> pX;
X<C>& g() {
if ( !pX ) throw 0; // Error: 'X<C>::t' uses undefined class …
Run Code Online (Sandbox Code Playgroud) 使用指向基类的指针调用类的虚拟成员函数当然是在C++中非常常见的事情.所以我觉得很奇怪,当你有一个成员指针而不是普通的指针时,似乎不可能做同样的事情.请考虑以下代码:
struct B
{
virtual void f();
};
struct D : B
{
virtual void f();
};
struct E
{
B b;
D d;
};
int main()
{
E e;
// First with normal pointers:
B* pb1 = &e.b; // OK
B* pb2 = &e.d; // OK, B is a base of D
pb1->f(); // OK, calls B::f()
pb2->f(); // OK, calls D::f()
// Now with member pointers:
B E::* pmb1 = &E::b; // OK
B E::* pmb2 = &E::d; …
Run Code Online (Sandbox Code Playgroud) 请考虑以下事项:
class CMyClass
{
public:
CMyClass()
{
printf( "Constructor\n" );
}
CMyClass( const CMyClass& )
{
printf( "Copy constructor\n" );
}
};
int main()
{
std::list<CMyClass> listMyClass;
listMyClass.resize( 1 );
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它产生以下输出:
构造函数
复制构造函数
现在我的问题是:我如何避免复制构造函数?或者换一种方式:如何在没有不必要的复制操作的情况下在STL容器内创建对象.有没有办法使用默认构造函数进行"就地"构造?
更新 - 答案到目前为止:
智能指针对我的应用来说太过分了.但我真的很想知道为什么不能这样做.这似乎是一件显而易见的事情.还有其他想法吗?如果它有效,我甚至会接受一个讨厌的黑客......
解
我想我刚从这里提出的所有评论和答案中找到了我的问题的解决方案.解决方案是构造一个空对象并将其保留,以便以后使用它来制作干净的副本.然后,您可以使用其中一个引用方法(如push_back或insert).这仍然为每个插入的新对象调用复制构造函数,但至少它不是默认构造函数和复制构造函数:
int main()
{
CMyClass Empty;
std::list<CMyClass> listMyClass;
for ( int c=0; c<10; ++c )
{
listMyClass.push_back( Empty );
}
return 0;
}
Run Code Online (Sandbox Code Playgroud) 是否有任何理由指定一个函数,因为final
该类已经final
?或者这是多余的?
class B
{
public:
virtual void f();
};
class D final : public B
{
public:
virtual void f() final; // Redundant final?
};
Run Code Online (Sandbox Code Playgroud)
说一下这是一个很好的经验法则:从创建整个类开始final
,只有final
在需要派生类和/或覆盖特定函数时才切换到创建单独的函数?
我知道NRVO允许函数构造一个对象并按值返回该对象而不需要复制或甚至移动操作的成本.它发现它也适用于嵌套函数调用,允许您从另一个函数调用的返回值构造对象.
请考虑以下程序及其输出,如注释中所示:(
Visual Studio 2017的输出,版本15.2,发布版本.)
#include <stdio.h>
class W
{
public:
W() { printf( "W::W()\n" ); }
W( const W& ) { printf( "W::W( const W& )\n" ); }
W( W&& ) { printf( "W::W( W&& )\n" ); }
W& operator=( const W& ) { printf( "W::operator=( const W& )\n" ); }
W& operator=( W&& ) { printf( "W::operator=( W&& )\n" ); }
~W() { printf( "W::~W()\n" ); }
void Transform() { printf( "W::Transform()\n" ); }
void Run() { printf( …
Run Code Online (Sandbox Code Playgroud) 请帮助我理解为什么类成员函数可以返回私有嵌套类对象,以及为什么可以在该私有嵌套类上调用成员函数,例如:
class Y
{
class X
{
public:
void f() { cout << "Hello World" << endl; }
};
public:
X g() { return X(); }
};
void h()
{
Y::X x; // Error, as expected: class Y::X is private.
x.f(); // Error.
Y y; // OK.
y.g().f(); // OK. But why???
}
Run Code Online (Sandbox Code Playgroud)
我使用GCC和Visual C++进行了测试,最后一行编译在两者上.我似乎无法在C++标准中找到任何可以使其有效的内容.任何想法为何有效?
编辑:
另一个观察:
void i()
{
Y y;
Y::X x2 = y.g(); // Error: class Y::X is private
x2.f(); // Error
auto x3 = y.g(); // …
Run Code Online (Sandbox Code Playgroud) 我刚刚发现,在将参数传递给宏时,不能总是使用大括号初始化.当ASSERT()宏无法编译时,我发现了这一点.但是,以下示例说明了此问题:
#include <iostream>
#include <string>
using namespace std;
#define PRINT_SIZE( f ) cout << "Size=" << (f).size() << endl;
int main()
{
PRINT_SIZE( string("ABC") ); // OK, prints: "Size=3"
PRINT_SIZE( string{"ABC"} ); // OK, prints: "Size=3"
PRINT_SIZE( string("ABCDEF",3) ); // OK, prints: "Size=3"
PRINT_SIZE( string{"ABCDEF",3} ); // Error: macro 'PRINT_SIZE' passed 2 arguments, but takes just 1
return 0;
}
Run Code Online (Sandbox Code Playgroud)
有没有理由不能使大括号初始化使用宏?
编辑:
我后来发现你也可以使用一个可变参数宏,这完全解决了这个问题:
#include <iostream>
#include <string>
using namespace std;
#define PRINT_SIZE( ... ) cout << "Size=" << (__VA_ARGS__).size() << …
Run Code Online (Sandbox Code Playgroud)