C++ nodiscard
1500 Words|Read in about 7 Min|本文总阅读量次
学习一下关于C++基础知识nodiscard。
1介绍
nodiscard是c++17引入的一种标记符,其语法一般为[[nodiscard]]或[nodiscard(“string”)],含义可以理解为“不应舍弃”。nodiscard一般用于标记函数的返回值或者某个类,当使用某个弃值表达式而不是cast to void 来调用相关函数时,编译器会发出相关warning。
2实例
2.1出现警告
1#include <iostream>
2using namespace std;
3
4[[nodiscard]] int calculateSum(int a, int b) {
5 return a + b;
6}
7
8int main() {
9 calculateSum(2, 3); // 没有使用返回值,可能会产生警告或错误
10 cout << 1 << endl;
11 return 0;
12}
如果在真实clion编译结果是没有异常,有一个警告。
如果是在线编译器,同样也会提示一个警告
同样也适用于枚举类
1#include <iostream>
2using namespace std;
3
4[[nodiscard]] int fi() //修饰函数返回值
5{
6 return 1;
7}
8
9class [[nodiscard]] C{}; //修饰类
10enum class [[nodiscard]] E{e1, e2}; //修饰枚举类
11
12C fc()
13{
14 return C();
15}
16
17E fe()
18{
19 return E::e1;
20}
21
22int main()
23{
24 fi(); //没有使用fi的返回值,告警:ignoring return value of 'int fi()', declared with attribute nodiscard
25 fc(); //没有使用fc的返回值,告警:ignoring returned value of type 'C', declared with attribute nodiscard
26 fe(); //没有使用fe的返回值,告警:ignoring returned value of type 'E', declared with attribute nodiscard
27 return 0;
28}
结果
1====================[ Build | CPPProject0710 | Debug ]==========================
2"D:\Clion\CLion 2022.2.1\bin\cmake\win\bin\cmake.exe" --build D:\project\CPPProject0710\cmake-build-debug --target CPPProject0710 -j 3
3[1/2] Building CXX object CMakeFiles/CPPProject0710.dir/main.cpp.obj
4D:/project/CPPProject0710/main.cpp: In function 'int main()':
5D:/project/CPPProject0710/main.cpp:23:7: warning: ignoring return value of 'int fi()', declared with attribute 'nodiscard' [-Wunused-result]
6 23 | fi(); //ignoring return value of 'int fi()', declared with attribute nodiscard
7 | ~~^~
8D:/project/CPPProject0710/main.cpp:3:19: note: declared here
9 3 | [[nodiscard]] int fi() //Modifies the return value of the function
10 | ^~
11D:/project/CPPProject0710/main.cpp:24:7: warning: ignoring returned value of type 'C', declared with attribute 'nodiscard' [-Wunused-result]
12 24 | fc(); //ignoring returned value of type 'C', declared with attribute nodiscard
13 | ~~^~
14D:/project/CPPProject0710/main.cpp:11:3: note: in call to 'C fc()', declared here
15 11 | C fc()
16 | ^~
17D:/project/CPPProject0710/main.cpp:8:21: note: 'C' declared here
18 8 | class [[nodiscard]] C{}; //Modifier class
19 | ^
20D:/project/CPPProject0710/main.cpp:25:7: warning: ignoring returned value of type 'E', declared with attribute 'nodiscard' [-Wunused-result]
21 25 | fe(); //ignoring returned value of type 'E', declared with attribute nodiscard
22 | ~~^~
23D:/project/CPPProject0710/main.cpp:16:3: note: in call to 'E fe()', declared here
24 16 | E fe()
25 | ^~
26D:/project/CPPProject0710/main.cpp:9:26: note: 'E' declared here
27 9 | enum class [[nodiscard]] E{e1, e2}; //Modified enum class
28 | ^
29[2/2] Linking CXX executable CPPProject0710.exe
30
31Build finished
2.2去除warning方法
将上述改成cast to void或者接收一个返回值就不会出现警告
1#include <iostream>
2using namespace std;
3[[nodiscard]] int fi() //Modifies the return value of the function
4{
5 return 1;
6}
7
8class [[nodiscard]] C{}; //Modifier class
9enum class [[nodiscard]] E{e1, e2}; //Modified enum class
10
11C fc()
12{
13 return C();
14}
15
16E fe()
17{
18 return E::e1;
19}
20
21int main()
22{
23 //fi(); //ignoring return value of 'int fi()', declared with attribute nodiscard
24 int ret = fi();
25 static_cast<void>(fi());
26 //fc(); //ignoring returned value of type 'C', declared with attribute nodiscard
27 C c = fc();
28 static_cast<void>(fc());
29 //fe(); //ignoring returned value of type 'E', declared with attribute nodiscard
30 E e = fe();
31 static_cast<void>(fe());
32 return 0;
33}
输出
1====================[ Build | CPPProject0710 | Debug ]==========================
2"D:\Clion\CLion 2022.2.1\bin\cmake\win\bin\cmake.exe" --build D:\project\CPPProject0710\cmake-build-debug --target CPPProject0710 -j 3
3[1/2] Building CXX object CMakeFiles/CPPProject0710.dir/main.cpp.obj
4[2/2] Linking CXX executable CPPProject0710.exe
5
6Build finished
2.3nodiscard失效
1#include <iostream>
2using namespace std;
3[[nodiscard]]int* fi() //Modifies the return value of the function
4{
5 return new int(1);
6}
7
8class [[nodiscard]] C{}; //Modifier class
9enum class [[nodiscard]] E{e1, e2}; //Modified enum class
10
11C* fc()
12{
13 return new C();
14}
15
16E&& fe()
17{
18 return E::e1;
19}
20
21int main()
22{
23 //还是这段代码,这里虽然转化成指针形式,但是依然会出现warning
24 fi();
25 fc();
26 fe();
27
28 return 0;
29}
结果
1====================[ Build | CPPProject0710 | Debug ]==========================
2"D:\Clion\CLion 2022.2.1\bin\cmake\win\bin\cmake.exe" --build D:\project\CPPProject0710\cmake-build-debug --target CPPProject0710 -j 3
3[1/2] Building CXX object CMakeFiles/CPPProject0710.dir/main.cpp.obj
4D:/project/CPPProject0710/main.cpp: In function 'E&& fe()':
5D:/project/CPPProject0710/main.cpp:18:15: warning: returning reference to temporary [-Wreturn-local-addr]
6 18 | return E::e1;
7 | ~~~^~
8D:/project/CPPProject0710/main.cpp: In function 'int main()':
9D:/project/CPPProject0710/main.cpp:23:7: warning: ignoring return value of 'int* fi()', declared with attribute 'nodiscard' [-Wunused-result]
10 23 | fi(); //ignoring return value of 'int fi()', declared with attribute nodiscard
11 | ~~^~
12D:/project/CPPProject0710/main.cpp:3:19: note: declared here
13 3 | [[nodiscard]]int* fi() //Modifies the return value of the function
14 | ^~
15[2/2] Linking CXX executable CPPProject0710.exe
16
17Build finished
上面显示只有fi()函数返回值存在[[nodiscard]]的warning操作,剩余E::e1的警告是出现了局部变量的引用,望读者不要这样写,这里只是为了举例说明。即类对象的引用和指针是可以做到去除[[nodiscard]]的warning操作的,普通函数的加引用或者指针依然会出现warning警告。
3.4在源码中举例
1//frameworks/native/services/surfaceflinger/DisplayHardware/HWC2.h
2namespace HWC2 {
3 class Display {
4public:
5 virtual ~Display();
6
7 virtual hal::HWDisplayId getId() const = 0;
8 virtual bool isConnected() const = 0;
9 virtual void setConnected(bool connected) = 0; // For use by Device only
10 virtual bool hasCapability(
11 aidl::android::hardware::graphics::composer3::DisplayCapability) const = 0;
12 virtual bool isVsyncPeriodSwitchSupported() const = 0;
13 virtual bool hasDisplayIdleTimerCapability() const = 0;
14 virtual void onLayerDestroyed(hal::HWLayerId layerId) = 0;
15
16 [[nodiscard]] virtual hal::Error acceptChanges() = 0;
17 [[nodiscard]] virtual base::expected<std::shared_ptr<HWC2::Layer>, hal::Error>
18 createLayer() = 0;
19 [[nodiscard]] virtual hal::Error getChangedCompositionTypes(
20 std::unordered_map<Layer*, aidl::android::hardware::graphics::composer3::Composition>*
21 outTypes) = 0;
22 [[nodiscard]] virtual hal::Error getColorModes(std::vector<hal::ColorMode>* outModes) const = 0;
23 // Returns a bitmask which contains HdrMetadata::Type::*.
24 [[nodiscard]] virtual int32_t getSupportedPerFrameMetadata() const = 0;
25 [[nodiscard]] virtual hal::Error getRenderIntents(
26 hal::ColorMode colorMode, std::vector<hal::RenderIntent>* outRenderIntents) const = 0;
27 [[nodiscard]] virtual hal::Error getDataspaceSaturationMatrix(hal::Dataspace dataspace,
28 android::mat4* outMatrix) = 0;
29
30 [[nodiscard]] virtual hal::Error getName(std::string* outName) const = 0;
31 [[nodiscard]] virtual hal::Error getRequests(
32 hal::DisplayRequest* outDisplayRequests,
33 std::unordered_map<Layer*, hal::LayerRequest>* outLayerRequests) = 0;
34 [[nodiscard]] virtual hal::Error getConnectionType(ui::DisplayConnectionType*) const = 0;
35 [[nodiscard]] virtual hal::Error supportsDoze(bool* outSupport) const = 0;
36 [[nodiscard]] virtual hal::Error getHdrCapabilities(
37 android::HdrCapabilities* outCapabilities) const = 0;
38 [[nodiscard]] virtual hal::Error getDisplayedContentSamplingAttributes(
39 hal::PixelFormat* outFormat, hal::Dataspace* outDataspace,
40 uint8_t* outComponentMask) const = 0;
41 [[nodiscard]] virtual hal::Error setDisplayContentSamplingEnabled(bool enabled,
42 uint8_t componentMask,
43 uint64_t maxFrames) const = 0;
44 [[nodiscard]] virtual hal::Error getDisplayedContentSample(
45 uint64_t maxFrames, uint64_t timestamp,
46 android::DisplayedFrameStats* outStats) const = 0;
47 [[nodiscard]] virtual hal::Error getReleaseFences(
48 std::unordered_map<Layer*, android::sp<android::Fence>>* outFences) const = 0;
49 [[nodiscard]] virtual hal::Error present(android::sp<android::Fence>* outPresentFence) = 0;
50 [[nodiscard]] virtual hal::Error setClientTarget(
51 uint32_t slot, const android::sp<android::GraphicBuffer>& target,
52 const android::sp<android::Fence>& acquireFence, hal::Dataspace dataspace) = 0;
53 [[nodiscard]] virtual hal::Error setColorMode(hal::ColorMode mode,
54 hal::RenderIntent renderIntent) = 0;
55 [[nodiscard]] virtual hal::Error setColorTransform(const android::mat4& matrix) = 0;
56 [[nodiscard]] virtual hal::Error setOutputBuffer(
57 const android::sp<android::GraphicBuffer>& buffer,
58 const android::sp<android::Fence>& releaseFence) = 0;
59 [[nodiscard]] virtual hal::Error setPowerMode(hal::PowerMode mode) = 0;
60 [[nodiscard]] virtual hal::Error setVsyncEnabled(hal::Vsync enabled) = 0;
61 [[nodiscard]] virtual hal::Error validate(nsecs_t expectedPresentTime, uint32_t* outNumTypes,
62 uint32_t* outNumRequests) = 0;
63 [[nodiscard]] virtual hal::Error presentOrValidate(nsecs_t expectedPresentTime,
64 uint32_t* outNumTypes,
65 uint32_t* outNumRequests,
66 android::sp<android::Fence>* outPresentFence,
67 uint32_t* state) = 0;
68 [[nodiscard]] virtual ftl::Future<hal::Error> setDisplayBrightness(
69 float brightness, float brightnessNits,
70 const Hwc2::Composer::DisplayBrightnessOptions& options) = 0;
71 [[nodiscard]] virtual hal::Error setActiveConfigWithConstraints(
72 hal::HWConfigId configId, const hal::VsyncPeriodChangeConstraints& constraints,
73 hal::VsyncPeriodChangeTimeline* outTimeline) = 0;
74 [[nodiscard]] virtual hal::Error setBootDisplayConfig(hal::HWConfigId configId) = 0;
75 [[nodiscard]] virtual hal::Error clearBootDisplayConfig() = 0;
76 [[nodiscard]] virtual hal::Error getPreferredBootDisplayConfig(
77 hal::HWConfigId* configId) const = 0;
78 [[nodiscard]] virtual hal::Error setAutoLowLatencyMode(bool on) = 0;
79 [[nodiscard]] virtual hal::Error getSupportedContentTypes(
80 std::vector<hal::ContentType>*) const = 0;
81 [[nodiscard]] virtual hal::Error setContentType(hal::ContentType) = 0;
82 [[nodiscard]] virtual hal::Error getClientTargetProperty(
83 aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness*
84 outClientTargetProperty) = 0;
85 [[nodiscard]] virtual hal::Error getDisplayDecorationSupport(
86 std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
87 support) = 0;
88 [[nodiscard]] virtual hal::Error setIdleTimerEnabled(std::chrono::milliseconds timeout) = 0;
89 [[nodiscard]] virtual hal::Error getPhysicalDisplayOrientation(
90 Hwc2::AidlTransform* outTransform) const = 0;
91};
92
93class Layer {
94public:
95 virtual ~Layer();
96
97 virtual hal::HWLayerId getId() const = 0;
98
99 [[nodiscard]] virtual hal::Error setCursorPosition(int32_t x, int32_t y) = 0;
100 [[nodiscard]] virtual hal::Error setBuffer(uint32_t slot,
101 const android::sp<android::GraphicBuffer>& buffer,
102 const android::sp<android::Fence>& acquireFence) = 0;
103 [[nodiscard]] virtual hal::Error setSurfaceDamage(const android::Region& damage) = 0;
104
105 [[nodiscard]] virtual hal::Error setBlendMode(hal::BlendMode mode) = 0;
106 [[nodiscard]] virtual hal::Error setColor(
107 aidl::android::hardware::graphics::composer3::Color color) = 0;
108 [[nodiscard]] virtual hal::Error setCompositionType(
109 aidl::android::hardware::graphics::composer3::Composition type) = 0;
110 [[nodiscard]] virtual hal::Error setDataspace(hal::Dataspace dataspace) = 0;
111 [[nodiscard]] virtual hal::Error setPerFrameMetadata(const int32_t supportedPerFrameMetadata,
112 const android::HdrMetadata& metadata) = 0;
113 [[nodiscard]] virtual hal::Error setDisplayFrame(const android::Rect& frame) = 0;
114 [[nodiscard]] virtual hal::Error setPlaneAlpha(float alpha) = 0;
115 [[nodiscard]] virtual hal::Error setSidebandStream(const native_handle_t* stream) = 0;
116 [[nodiscard]] virtual hal::Error setSourceCrop(const android::FloatRect& crop) = 0;
117 [[nodiscard]] virtual hal::Error setTransform(hal::Transform transform) = 0;
118 [[nodiscard]] virtual hal::Error setVisibleRegion(const android::Region& region) = 0;
119 [[nodiscard]] virtual hal::Error setZOrder(uint32_t z) = 0;
120
121 // Composer HAL 2.3
122 [[nodiscard]] virtual hal::Error setColorTransform(const android::mat4& matrix) = 0;
123
124 // Composer HAL 2.4
125 [[nodiscard]] virtual hal::Error setLayerGenericMetadata(const std::string& name,
126 bool mandatory,
127 const std::vector<uint8_t>& value) = 0;
128
129 // AIDL HAL
130 [[nodiscard]] virtual hal::Error setBrightness(float brightness) = 0;
131 [[nodiscard]] virtual hal::Error setBlockingRegion(const android::Region& region) = 0;
132};
133}
举例说明
1//frameworks/native/services/surfaceflinger/DisplayHardware/HWC2.h
2[[nodiscard]] virtual hal::Error getChangedCompositionTypes(
3 std::unordered_map<Layer*, aidl::android::hardware::graphics::composer3::Composition>*
4 outTypes) = 0;
5//frameworks/native/services/surfaceflinger/DisplayHardware/HWComposer.cpp
6error = hwcDisplay->getChangedCompositionTypes(&changedTypes);
可以发现这里的调用都是带有返回值的。
3总结
在上面的例子中,函数calculateSum
被标记为[[nodiscard]],但在main
函数中,它的返回值没有被使用。编译器可能会发出警告或错误,提醒开发者注意。
需要注意的是,[[nodiscard]]属性只是一种编译器提供的静态检查机制,并不能强制要求开发者一定要使用函数的返回值。但通过标记函数为[[nodiscard]],可以增加代码的可读性和可维护性,减少潜在的错误。